【问题标题】:RTTI for generic type with interface type constraint具有接口类型约束的泛型类型的 RTTI
【发布时间】:2014-05-07 03:25:02
【问题描述】:

是否可以检查具有接口类型约束的泛型类型实例的 RTTI 信息?这个问题可能有点模棱两可,所以我创建了一个示例控制台应用程序来展示我正在尝试做的事情:

program Project3;

{$APPTYPE CONSOLE}

uses
  RTTI,
  SysUtils,
  TypInfo;

type
  TMyAttribute = class(TCustomAttribute)
  strict private
    FName: string;
  public
    constructor Create(AName: string);
    property Name: string read FName;
  end;

  IMyObjectBase = interface
  ['{E063AD44-B7F1-443C-B9FE-AEB7395B39DE}']
    procedure DoSomething;
  end;

  TMyObjectBase = class(TInterfacedObject, IMyObjectBase)
  public
    procedure DoSomething; virtual;
  end;

  [TMyAttribute('First')]
  TMyFirstRealClass = class(TMyObjectBase)
  public
    procedure DoSomethingDifferent;
  end;

  [TMyAttribute('Second')]
  TMySecondRealClass = class(TMyObjectBase)
  public
    procedure BeSomethingDifferent;
  end;

  TGenericClass<I: IMyObjectBase> = class
  public
    function GetAttributeName(AObject: I): string;
  end;


{ TMyAttribute }

constructor TMyAttribute.Create(AName: string);
begin
  FName := AName;
end;

{ TMyObjectBase }

procedure TMyObjectBase.DoSomething;
begin
end;

{ TMyFirstRealClass }

procedure TMyFirstRealClass.DoSomethingDifferent;
begin
end;

{ TMySecondRealClass }

procedure TMySecondRealClass.BeSomethingDifferent;
begin
end;

{ TGenericClass<I> }

function TGenericClass<I>.GetAttributeName(AObject: I): string;
var
  LContext: TRttiContext;
  LProp: TRttiProperty;
  LAttr: TCustomAttribute;
begin
  Result := '';
  LContext := TRttiContext.Create;
  try
    for LAttr in LContext.GetType(AObject).GetAttributes do
    // ----> [DCC Error] E2250 There is no overloaded version of 'GetType' that can be called with these arguments
      if LAttr is TMyAttribute then
      begin
        Result := TMyAttribute(LAttr).Name;
        Break;
      end;
  finally
    LContext.Free;
  end;
end;

var
  LFirstObject: IMyObjectBase;
  LSecondObject: IMyObjectBase;
  LGeneric: TGenericClass<IMyObjectBase>;
begin
  try
    LFirstObject := TMyFirstRealClass.Create;
    LSecondObject := TMySecondRealClass.Create;

    LGeneric := TGenericClass<IMyObjectBase>.Create;

    Writeln(LGeneric.GetAttributeName(LFirstObject));
    Writeln(LGeneric.GetAttributeName(LSecondObject));

    LGeneric.Free;

    LFirstObject := nil;
    LSecondObject := nil;

    Readln;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

我需要检查传入的对象 (AObject),而不是通用接口 (I)。 (德菲 2010)。 感谢您的建议。

【问题讨论】:

  • 您是否尝试过类似“for LAttr in LContext.GetType(TObject(AObject)).GetAttributes do”? Delphi 2010 中添加了对象强制转换接口。这不是我喜欢做的事情,但它可以在这种情况下提供帮助。
  • 是的,这似乎是显而易见的解决方案,但它显示“无效类型转换”。
  • 好的,测试过了,还是不行。现在将编辑我的答案以删除该选项。
  • 您必须使用as 运算符将接口转换为对象,例如:for LAttr in LContext.GetType((AObject as TObject).ClassType).GetAttributes。阅读文档:Casting Interface References to Objects

标签: delphi generics interface rtti


【解决方案1】:

两种可能的解决方案如下:

1) 我对此进行了测试,它可以工作 (XE4):

for LAttr in LContext.GetType((AObject as TObject).ClassType).GetAttributes do

2)我对此进行了测试,它可以工作(XE4):

for LAttr in LContext.GetType(TMyObjectBase(AObject).ClassType).GetAttributes do

3) 在返回对象的接口上创建方法并使用它来检查对象:

IMyObjectBase = interface
['{E063AD44-B7F1-443C-B9FE-AEB7395B39DE}']
  procedure DoSomething;
  function GetObject: TObject;
end;

TMyObjectBase = class(TInterfacedObject, IMyObjectBase)
public
  procedure DoSomething; virtual;
  function GetObject: TObject;
end;

{ TMyObjectBase }

function TMyObjectBase.GetObject: TObject;
begin
  Result := Self;
end;

然后这样称呼它:

for LAttr in LContext.GetType(AObject.GetObject.ClassType).GetAttributes do

【讨论】:

  • 这适用于以下小修改......我需要将“.ClassType”添加到以下内容:对于 LContext.GetType(AObject.GetObject.ClassType).GetAttributes 中的 LAttr。我不确定这是否是一种“纯粹主义”的做法,但它仍然有效。
  • @RickWheeler Casting to TMyObjectBase 似乎在表面上也有效,所以我更新了答案以反映这一点。正如你所说,“纯粹主义者”可能想跟我说一句话:)
  • 您不需要让接口公开方法来检索实现对象。您可以直接将接口转换为TObjectfor LAttr in LContext.GetType((AObject as TObject).ClassType).GetAttributes do
  • @RemyLebeau 谢谢,我用硬演员测试过但失败了,所以我认为软演员也会失败。将其添加为第三个选项。你知道为什么软转换起作用而硬转换被编译器抛出吗?
  • @RickWheeler 在 Delphi 2010 中,您需要更多地帮助编译器。你必须写IInterface(AObject) as TObjectTObject(IInterface(AObject))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-05
  • 2018-03-05
相关资源
最近更新 更多