如何将泛型列表作为参数传递给泛型方法

时间:2018-11-24 11:46:26

标签: delphi generics type-inference

当尝试将泛型列表的实例传递给泛型方法,而将泛型数组传递给方法(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.

1 个答案:

答案 0 :(得分:2)

Delphi希望您在泛型方法上指定类型参数,因为它从封闭的泛型类型推断出的类型相当有限。

我们可以称之为类型擦除,此时编译器看到SomeList的类型为TList<TBaseClass>,但不知道它是封闭的泛型类型。这意味着它无法从传递的TBaseClass中推断出SomeList并看到“哦,那是TList<T>,其中TTBaseClass”。

所以你必须写:

TSomeClass.DoSomethingWithGenericList<TBaseClass>(SomeList);

同样适用于TArray<T>重载。

对于array of T是开放数组(array of ...作为参数类型不是动态数组!),编译器知道在传递{{ 1}}变量。