【问题标题】:RTTI: Can I Get a Type by Name?RTTI:我可以按名称获取类型吗?
【发布时间】:2009-11-03 16:53:04
【问题描述】:

给定一个包含类型名称的文本字符串,有什么方法可以获取适当的类型本身吗?

我想做这样的事情:

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 单元,但没有看到我在寻找什么。这可能吗?

【问题讨论】:

  • 你希望你能用你创建的对象做什么样的“东西”?
  • 从中获取一个接口。它是持久性方案的一部分。
  • 谁说它有一个可以“抓取”的界面?如果你对类型有足够的了解,知道它实现了一个特定的接口,那么你就不需要做上面的 sn-p 代码所做的事情了。
  • @Ken:不一定。泛型类型可以实现非泛型接口。它们可以来自非泛型类型。因此,我可以通过将实例分配给祖先类,从中获取接口,而无需明确知道模板类型“T”是什么。甚至根本就知道泛型类型。

标签: delphi delphi-2010 rtti


【解决方案1】:

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

【讨论】:

  • 好吧,粗鲁。看起来你是对的。这否定了我的一个很酷的想法。感谢您的信息。
  • 仍然很好奇是否有办法从名称中获取类型。即使我不能完全按照我想要的方式使用它。
【解决方案2】:

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

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

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

【讨论】:

  • 太棒了!感谢您的信息。
【解决方案3】:

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

一个可能的用法示例:

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 方法并扩展接口以做一些更有用的事情。

【讨论】:

  • 谢谢。这几乎正​​是我一直在做的事情(很久以前从 Delphi 的 TPersistent 得到这个想法)。您的建议是我们已经提出的(注册每种模板类型)并且效果很好。我希望有一些更灵活和动态的东西,但看起来我不会得到它。再次感谢。
  • 这很容易变得灵活和动态。你唯一不能做的就是处理你没有计划的类型。
【解决方案4】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 2011-07-30
    相关资源
    最近更新 更多