Приведение члена универсального типа к TObject? - PullRequest
2 голосов
/ 22 февраля 2011

Я сейчас думаю о сценарии, в котором я хочу универсальный класс, который вызывает Free для своих элементов IF , которые относятся к типу объектов. Поэтому я попробовал следующее:

if (PTypeInfo (TypeInfo (T)).Kind = tkClass) then
  begin
  RttiType := RttiContext.GetType (TypeInfo (T));
  FreeMethod := RttiType.GetMethod ('Free');
  if (FreeMethod <> nil) then
    FreeMethod.Invoke (FInstance, []);
  end;

К сожалению, последняя строка не компилируется, что неудивительно, поскольку типы не совпадают. Вопрос: могу ли я получить его для компиляции? Я попытался привести к Pointer, а затем к TObject, но это дает мне недопустимую ошибку приведения типа. Есть ли способ получить FInstance : T в TObject ссылку, которую я затем могу передать Invoke?

Или есть другой способ добиться того, чего я хочу? Обратите внимание, что весь смысл в том, чтобы получить все в этом классе, поэтому я не хочу создавать TObjectMyClass, который просто принимает объекты.

Спасибо за вашу помощь.

Ответы [ 4 ]

5 голосов
/ 22 февраля 2011

Разве этого не достаточно?

if PTypeInfo(TypeInfo(T))^.Kind = tkClass then
  TObject(FInstance).Free;
2 голосов
/ 22 февраля 2011

Прямое приведение к TObject, кажется, работает в Delphi 2010:

FreeMethod.Invoke (TObject(FInstance), []);

Полный пример:

implementation

uses TypInfo, Rtti;

{$R *.dfm}

type
  TTest<T> = class
    FInstance : T;
    procedure F;
  end;

procedure TForm1.FormCreate(Sender: TObject);
var
  O : TTest<TObject>;
begin
  O := TTest<TObject>.Create;
  O.FInstance := TStringList.Create;
  O.F;
  O.Free;
end;

{ TTest<T> }

procedure TTest<T>.F;
var
  RttiType : TRttiType;
  FreeMethod : TRttiMethod;
  RttiContext : TRttiContext;
begin
  if (PTypeInfo (TypeInfo (T)).Kind = tkClass) then
  begin
    RttiType := RttiContext.GetType (TypeInfo (T));
    FreeMethod := RttiType.GetMethod ('Free');
    if (FreeMethod <> nil) then
      FreeMethod.Invoke (TObject(FInstance), []);
  end;
end;
2 голосов
/ 22 февраля 2011

Это попахивает плохим дизайном для меня.Один из пунктов обобщений заключается в том, чтобы отказаться от таких решений динамического типа, как этот.

Если вы действительно используете функцию обобщений, то для меня было бы более разумно иметь подкласс с ограниченным параметром типаберут только TObject потомков.Поскольку вы должны статически решить, как вы собираетесь создавать экземпляр универсального класса, нетрудно использовать TMyObjectClass, когда T является классом, и использовать TMyClass в другом месте.

Я полагаюВы будете вынуждены принять подход, который вы используете, если один контейнер должен содержать как объекты, так и не объекты.Но если это не так, то что-то мне не нравится.

1 голос
/ 22 февраля 2011

На самом деле, я только что нашел ответ сам. TValue.From делает трюк:

if (PTypeInfo (TypeInfo (T)).Kind = tkClass) then
  begin
  RttiType := RttiContext.GetType (TypeInfo (T));
  FreeMethod := RttiType.GetMethod ('Free');
  if (FreeMethod <> nil) then
    FreeMethod.Invoke (TValue.From <T> (FInstance), []);
  end;
...