【问题标题】:Generics: What's a "CONSTRUCTOR constraint"?泛型:什么是“构造约束”?
【发布时间】:2008-12-20 20:17:07
【问题描述】:

我制作了一个自定义 TObjectList 后代,旨在保存基对象类的子类。它看起来像这样:

interface
   TMyDataList<T: TBaseDatafile> = class(TObjectList<TBaseDatafile>)
   public
      constructor Create;
      procedure upload(db: TDataSet);
   end;

implementation

constructor TMyDataList<T>.Create;
begin
   inherited Create(true);
   self.Add(T.Create);
end;

我希望每个新列表都以其中一个空白对象开始。这很简单,对吧?但是编译器不喜欢它。它说:

“无法在类型参数声明中创建没有 CONSTRUCTOR 约束的新实例” 我只能假设这是与泛型相关的东西。任何人都知道发生了什么以及如何使这个构造函数工作?

【问题讨论】:

    标签: delphi generics constructor delphi-2009


    【解决方案1】:

    您正在尝试通过T.Create 创建T 的实例。这不起作用,因为编译器不知道您的泛型类型具有无参数构造函数(请记住:这不是必需的)。为了纠正这个问题,你必须创建一个构造函数约束,如下所示:

    <T: constructor>
    

    或者,在您的具体情况下:

    <T: TBaseDatafile, constructor>
    

    【讨论】:

    • 呸。在这种情况下,编译器确实知道 TBaseDataFile 有一个不带参数的虚拟构造函数。
    • @Mason:我不能代表 Delphi,一般来说你是对的,编译器 可以 知道它是否只是查看了正确的位置。但是,这不是它的工作方式,以便使代码更加明确。 C++ 是另一回事:在可比较的情况下,它不需要这样的约束。
    • @Konrad:没错,像 FPC 3.1.1 这样的好的编译器不需要这样的约束,这在那里工作得很好。显然 Delphi 编译器不好,这也是它几乎死掉的原因之一。
    【解决方案2】:

    只是对一个老问题的快速更新..

    您不需要构造函数约束,也可以通过像这样使用 RTTI(使用带有 XE2 的 RTTI 或 System.RTTI)对带有参数的对象执行此操作

    constructor TMyDataList<T>.Create;
    var
      ctx: TRttiContext;
    begin
       inherited Create(true);
       self.Add(
         ctx.
         GetType(TClass(T)).
         GetMethod('create').
         Invoke(TClass(T),[]).AsType<T>
       );
    end;
    

    如果你有参数,只需像这样添加它们

    constructor TMyDataList<T>.Create;
    var
      ctx: TRttiContext;
    begin
       inherited Create(true);
       self.Add(
         ctx.
         GetType(TClass(T)).
         GetMethod('create').
         Invoke(TClass(T),[TValue.From('Test'),TValue.From(42)]).AsType<T>
       );
    end;
    

    【讨论】:

    • 其实写TBaseDatafile(T).Create是最简单的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多