当尝试将泛型列表的实例传递给泛型方法,而将泛型数组传递给方法(1)编译器时,我遇到了一个奇怪的Delphi(Tokyo)编译器的限制。
(1) class procedure DoSomethingWithDynamicArray<T: class>(AArray: array of T);
(2) class procedure DoSomethingWithGenericArray<T: class>(AArray: TArray<T>);
(3) class procedure DoSomethingWithGenericList<T: class>(AList: TList<T>);
但是当将相同的数组传递给带有签名(2)的方法时,Delphi会报错:
[dcc32 Error] Project8.dpr(49): E2010 Incompatible types: 'System.TArray<....TSomeClass.DoSomethingWithGenericArray.T>' and 'System.TArray<....TBaseClass>'
即使将TArray<T>
声明为array of <T>
。
将通用列表传递给方法(3)时,会发生相同的错误。
这种限制的原因是什么?但是主要,如何在Delphi中实现这些功能? (例如,在C#中没有此类限制)。
我阅读了有关<T>
可能继承的一些解释,但是我不接受这样的参数,因为数组可能发生相同的问题,并且编译器接受它:
SomeArray: TArray<TBaseClass>;
SomeArray := [TBaseClass.Create, TDescendantClass.Create,
TGrandDescendantClass.Create];
TSomeClass.DoSomethingWithDynamicArray(SomeArray);
更新:示例
program Project8;
uses
System.SysUtils, System.Generics.Collections;
type
TBaseClass = class
end;
TDescendantClass = class(TBaseClass)
end;
TGrandDescendantClass = class(TDescendantClass)
end;
TSomeClass = class
class procedure DoSomethingWithDynamicArray<T: class>(AArray: array of T);
class procedure DoSomethingWithGenericArray<T: class>(AArray: TArray<T>);
class procedure DoSomethingWithGenericList<T: class>(AList: TList<T>);
end;
var
SomeArray: TArray<TBaseClass>;
SomeList: TList<TBaseClass>;
class procedure TSomeClass.DoSomethingWithDynamicArray<T>(AArray: array of T);
begin
end;
class procedure TSomeClass.DoSomethingWithGenericArray<T>(AArray: TArray<T>);
begin
end;
class procedure TSomeClass.DoSomethingWithGenericList<T>(AList: TList<T>);
begin
end;
begin
try
SomeArray := [TBaseClass.Create, TDescendantClass.Create,
TGrandDescendantClass.Create];
TSomeClass.DoSomethingWithDynamicArray(SomeArray);
TSomeClass.DoSomethingWithGenericArray(SomeArray); //E2010: Incompatible type
SomeList := TList<TBaseClass>.Create;
SomeList.AddRange([TBaseClass.Create, TDescendantClass.Create,
TGrandDescendantClass.Create]);
TSomeClass.DoSomethingWithGenericList(SomeList); //E2010: Incompatible type
except on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
答案 0 :(得分:2)
Delphi希望您在泛型方法上指定类型参数,因为它从封闭的泛型类型推断出的类型相当有限。
我们可以称之为类型擦除,此时编译器看到SomeList
的类型为TList<TBaseClass>
,但不知道它是封闭的泛型类型。这意味着它无法从传递的TBaseClass
中推断出SomeList
并看到“哦,那是TList<T>
,其中T
是TBaseClass
”。
所以你必须写:
TSomeClass.DoSomethingWithGenericList<TBaseClass>(SomeList);
同样适用于TArray<T>
重载。
对于array of T
是开放数组(array of ...
作为参数类型不是动态数组!),编译器知道在传递{{ 1}}变量。