RTTI:我可以按姓名获取类型吗?

时间:2009-11-03 16:53:04

标签: delphi delphi-2010 rtti

给定一个包含类型名称的文本字符串,是否有某种方法可以获得适当的类型?

我希望做这样的事情:

type
  TSomeType<T> = class
    // yadda yadda
  end;

procedure DoSomething;
var
  obj : TObject;
begin
  o := TSomeType<GetTypeByName('integer')>.Create;
  // do stuff with obj
end;

我在线查看了几个RTTI解释并查看了Delphi单元,但没有看到我在寻找什么。这可能吗?

4 个答案:

答案 0 :(得分:7)

不,泛型完全是编译时间。

答案 1 :(得分:5)

您始终可以将您的类型注册到某种注册表(由字符串列表或字典管理)并创建工厂函数,然后返回相应的对象。不幸的是,你必须提前知道你需要什么类型。类似于Delphi函数的RegisterClass和FindClass(在classes单元中)。我的想法是直接将通用模板类型放入列表中。

可能的用法示例:

RegisterCustomType('Integer',TSomeType<Integer>);
RegisterCustomType('String',TSomeType<String>);

if FindCustomType('Integer') <> nil then
  O := FindCustomType('Integer').Create;

编辑:这是一个特殊的简单实现,它使用Generics.Collections中的tDictionary来处理注册表存储...我将把它提取到有用的方法中,作为读者的简单练习。

var
  o : TObject;
begin
  TypeDict := TDictionary<String,TClass>.Create;
  TypeDict.Add('integer',TList<integer>);
  if TypeDict.ContainsKey('integer') then
    o := TypeDict.Items['integer'].Create;
  if Assigned(o) then
    ShowMessage(o.ClassName);
end;

另一个编辑:昨晚我正在考虑这个问题,并发现了另一种可以融入这个概念的技术。接口。这是一个快速无所作为的例子,但可以很容易地扩展:

TYPE
  ITest = interface
    ['{0DD03794-6713-47A0-BBE5-58F4719F494E}']
  end;

  TIntfList<t> = class(TList<T>,ITest)
  public
    function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;

procedure TForm1.Button7Click(Sender: TObject);
var
  o : TObject;
  fTestIntf : ITest;
begin
  TypeDict := TDictionary<String,TClass>.Create;
  TypeDict.Add('integer',TIntfList<integer>);
  if TypeDict.ContainsKey('integer') then
    o := TypeDict.Items['integer'].Create;
  if Assigned(o) and Supports(o,ITest,fTestIntf) then
    ShowMessage(o.ClassName);
end;

当然,您必须实现QueryInterface,_AddRef和_Release方法并扩展接口以执行更有用的操作。

答案 2 :(得分:5)

Delphi 2010中的新RTTI单元有一种检索单元接口部分中声明的类型的方法。对于由TRttiType实例表示的任何给定类型,TRttiType.QualifiedName属性返回一个名称,以便稍后可以与TRttiContext.FindType一起使用以检索该类型。限定名称是完整的单元名称(包括名称空间,如果存在),后跟一个“。”,后跟完整的类型名称(如果嵌套则包括外部类型)。

因此,您可以使用TRttiType检索整数类型的表示形式(以context.FindType('System.Integer')的形式)。

但是这个机制不能用于检索在编译时没有实例化的泛型类型的实例化;运行时实例化需要生成运行时代码。

答案 3 :(得分:0)

如果您忘记了泛型和基本类型,“RegisterClass”函数会很有帮助。但它不适用于泛型或基本类型。