如何将泛型列表作为参数传递给泛型方法
How to pass a generic list as a parameter to generic method
我遇到了一个奇怪的 Delphi (Tokyo) 编译器的限制,当我尝试将泛型列表的实例传递给泛型方法,而将泛型数组传递给方法 (1) 时,编译器接受并且一切都按预期工作。
(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.
Delphi 希望您在泛型方法上指定类型参数,因为它对封闭泛型类型的类型推断非常有限。
我们可以调用该类型擦除,此时编译器看到 SomeList
的类型是 TList<TBaseClass>
但不知道它是一个封闭的泛型类型。这意味着它无法从传递的 SomeList
推断出 TBaseClass
并查看 "Oh, that is a TList<T>
with T
being TBaseClass
".
所以你必须写:
TSomeClass.DoSomethingWithGenericList<TBaseClass>(SomeList);
同样适用于 TArray<T>
重载。
对于array of T
这是一个开放数组(array of ...
作为参数类型不是动态数组!)编译器知道推断类型传递 SomeArray
变量时。
我遇到了一个奇怪的 Delphi (Tokyo) 编译器的限制,当我尝试将泛型列表的实例传递给泛型方法,而将泛型数组传递给方法 (1) 时,编译器接受并且一切都按预期工作。
(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.
Delphi 希望您在泛型方法上指定类型参数,因为它对封闭泛型类型的类型推断非常有限。
我们可以调用该类型擦除,此时编译器看到 SomeList
的类型是 TList<TBaseClass>
但不知道它是一个封闭的泛型类型。这意味着它无法从传递的 SomeList
推断出 TBaseClass
并查看 "Oh, that is a TList<T>
with T
being TBaseClass
".
所以你必须写:
TSomeClass.DoSomethingWithGenericList<TBaseClass>(SomeList);
同样适用于 TArray<T>
重载。
对于array of T
这是一个开放数组(array of ...
作为参数类型不是动态数组!)编译器知道推断类型传递 SomeArray
变量时。