delphigenericsrecordrttidelphi-12-athens

How do I make a generic method that can convert all strings in a record to lowercase in Delphi?


I want a procedure that does something like this:

procedure RecordStringToLower(var MyRecord);
begin
  // 1. Loop through all fields
  // 2. Find string fields
  // 3. Convert all string fields to lowercase
end;

I know there are probably various ways to accomplish this, but it'll probably need to happen via generics and RTTI?. Any suggestions?

I'm not picky at all in terms of how the procedure or function works.


I tried a couple of different things, and this is the closest that I came, but it doesn't work:

class procedure TRecordHelper.RecordStringToLower<T>(var ARecord: T);
begin
  var Context := TRttiContext.Create;
  try
    var RttiType := Context.GetType(TypeInfo(T));
    for var Field in RttiType.GetFields do
    begin
      if (Field.FieldType.TypeKind = TTypeKind.tkString) then
        Field.SetValue(@ARecord, Field.GetValue(@ARecord).AsString.ToLower);
    end;
  finally
    Context.Free;
  end;
end;

I don't understand RTTI enough.


Solution

  • You are on the right track, you are just looking for the wrong type kind. Each string type has its own TTypeKind value, ie:

    tkString for ShortString

    tkUString for UnicodeString

    tkLString for AnsiString

    tkWString for WideString

    So, make sure you handle all of the kinds of strings your code actually uses, eg:

    class procedure TRecordHelper.RecordStringToLower<T>(var ARecord: T);
    begin
      var Context := TRttiContext.Create;
      try
        var RttiType := Context.GetType(TypeInfo(T));
        for var Field in RttiType.GetFields do
        begin
          case Field.FieldType.TypeKind of
            TTypeKind.tkString,
            TTypeKind.tkUString,
            TTypeKind.tkLString,
            TTypeKind.tkWString:
              Field.SetValue(@ARecord, Field.GetValue(@ARecord).AsString.ToLower);
          end;
        end;
      finally
        Context.Free;
      end;
    end;