Я хотел бы заполнить поле универсального объекта во время выполнения, используя D2010.
program generic_rtti_1;
{$APPTYPE CONSOLE}
uses
SysUtils, rtti;
type
TMyObject = class
FField1: string;
end;
TGeneric<TElement: class> = class
procedure FillFields(Element: TElement);
end;
procedure TGeneric<TElement>.FillFields(Element: TElement);
var
ctx: TRttiContext;
begin
ctx := TRttiContext.Create();
ctx.GetType(TypeInfo(TElement)).GetField('FField1').
SetValue(@Element, TValue.FromVariant('Some string'));
ctx.Free();
end;
Когда выполняется строка ctx.Free();
, я получаю AV по строке 21986 в System.pas (функция _IntfClear ()). Это называется с FContextToken := nil
в rtti.pas. (На самом деле, SetValue
-индуцированный AV всплывает, если я вступаю в SetValue
, однако, если перешагнуть через него, сообщается только о ctx.Free
-индуцированном. См. Ниже.)
Если я удаляю ctx.Free();
, при вызове SetValue(@Element, TValue.FromVariant('Some string'));
появляется AV. Это тоже в строке 21986 в System.pas.
Пытаясь разобраться в этом беспорядке, я заменил
ctx.GetType(TypeInfo(TElement)).GetField('FField1').
SetValue(@Element, TValue.FromVariant('Field 1 is set'));
с этим:
rType := ctx.GetType(TypeInfo(TElement));
rField := rType.GetField('FField1');
Val := TValue.FromVariant('Field 1 is set');
rField.SetValue(@Element, Val);
На этот раз я не получил ошибку, однако WriteLn(MyObject.FField1)
напечатал пустую строку. (AV снова появляется, если я комбинирую SetValue
и TValue.FromVariant
, т.е. пишу rField.SetValue(@Element, TValue.FromVariant('Field 1 is set'));
.
Чтобы точно определить виновную строку, я закомментировал строку за строкой, заменив закомментированный код составным оператором. Случайно я забыл закомментировать вышеприведенную строку Val := TValue.FromVariant('Field 1 is set');
, из-за которой AV снова исчезает (все еще вызывая rField.SetValue(@Element, TValue.FromVariant('Field 1 is set'));
). (Обратите внимание, что я на самом деле не использую Val
в проблемном вызове, но AV исчезает.)
Я немного потерян в этот момент.
Для полноты картины вот как я хотел бы использовать приведенный выше код:
var
Generic: TGeneric<TMyObject>;
MyObject: TMyObject;
begin
MyObject := TMyObject.Create();
Generic := TGeneric<TMyObject>.Create();
Generic.FillFields();
WriteLn(MyObject.FField1);
Generic.Free();
MyObject.Free();
ReadLn;
end;
end.
Кто-нибудь знает, что я делаю не так? (Это вообще возможно? Есть ли лучшие способы сделать это с помощью дженериков?)