为泛型对象列表创建对象

5

我不确定Delphi是否有这个功能。我已经搜索了一下,但好像找不到答案(例如示例或表明它不可能):

我有一个通用的列表类,并且我想创建该通用类型的实例。例如:

type
  TTypeA = class(TObject);

procedure Test;
var
  MyList: TobjectList<TTypeA>;
  NewListObject: TTypeA;
begin
  MyList := TObjectList<TTypeA>.Create;
  NewListObject := MyList.xxx //what to put on the xxx
end;

是否可能创建一个函数xxx来创建一个新的TTypeA类型的对象?

@jeroen:感谢您下面的答案。但是,我在我的问题中忘记了一个重要细节:

我希望这段代码适用于任何其他类型,而不需要事先了解TObjectList的类型T。我可能会创建以下列表:

MyList: TObjectList<TCar>;
MyList: TObjectList<TBike>;

不知道MyList是否包含TCar或TBike(两者都是从同一基类派生且构造函数相等),我想向MyList添加新项。

根据Uwe Raabe的建议,我修改了我的类:

TMyObjectList<T:class, constructor> = class(TMyBaseObjectList<T>)

其中TMyBaseObjectList定义为

TMyBaseObjectList<T:TMyBaseObject> = class(TObjectList)

现在我遇到了一个问题:

类型参数“T”与类型“T:TMyBaseObject”不兼容。

5个回答

3

你已经知道类型了,为什么不直接写呢?

NewListObject := TTypeA.Create;
MyList.Add(NewListObject);

这里自然而然的方式是这样做。如果你想让容器创建对象,你需要创建一个派生类,该类了解一些关于要创建实例的通用类型的信息。构造函数的约束可能会在此处有所帮助。
type
  TMyObjectList<T:class, constructor> = class(TObjectList<T>)
  public
    function NewObject: T;
  end;

function TMyObjectList<T>.NewObject: T;
begin
  result := T.Create;
end;

注意:此方法仅适用于实际类型具有名为Create的无参数构造函数的情况。

更新:这将有所帮助。

  TMyObjectList<T:constructor, TMyBaseObject> = class(TObjectList<T>)
  public
    function NewObj: T;
  end;

0

我猜这是不可能的。除非你的列表中有项目,在这种情况下,你可以这样做:

  NewListObject := MyList[0].ClassType.NewInstance as TTypeA;

直接调用NewInstance不是一个好主意,因为它不会调用构造函数。 - Mason Wheeler
我没有意识到,谢谢你指出来。不管怎样,Uwe的答案看起来是最好的解决方案。 - Ville Krumlinde

0

或者,您可以从TCollection继承您的列表类,从TCollectionItem继承您的项,并将它们用作基类。它们已经内置了所有这些管道。使用您的示例:

type
    TTypeA = class(TCollectionItem);

procedure Test;
var
    MyList: TCollection;
    NewListObject: TTypeA;

begin
    MyList := TCollection.Create(TTypeA);
    NewListObject := MyList.Add;
end;

编辑:我知道,它没有使用泛型,但是你可以参考TCollection和TCollectionItem获取更多的设计思路,特别是在处理所有权、通知和生命周期管理方面。


0
据我所知,在泛型类中只能使用无参数构造函数来定义你的泛型类型。
解决这个问题的一个“变通方法”是使用匿名方法来创建对象,但这意味着你需要创建许多方法。
至于其他问题……
TMyObjectList<T:class, constructor> = class(TMyBaseObjectList<T>)
TMyBaseObjectList<T:TMyBaseObject> = class(TObjectList)

我相信正确的声明应该是:

TMyObjectList<T:TMyBaseObject, constructor> = class(TMyBaseObjectList<T>)
TMyBaseObjectList<T:TMyBaseObject> = class(TObjectList)

TMyBaseObjectList已经强制T的类型为TMyBaseObject。如果您在TMyObjectList中声明T:class,则无法满足TMyBaseObjectList的要求。


0
xxx 处,输入以下内容:TTypeA.Create(...); 其中 ... 是您的构造函数参数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接