Delphi 2010中返回通用接口的通用方法

7
给定以下代码,这是实际代码的非常简化版本,我收到了以下错误信息:
[DCC Error] Unit3.pas(31): E2010 Incompatible types: 'IXList<Unit3.TXList<T>.FindAll.S>' and 'TXList<Unit3.TXList<T>.FindAll.S>'
在 FindAll 函数中。
我真的看不出来为什么,因为之前非常相似的函数没有问题。
有人能解释一下吗? 是我的问题还是编译器的 bug?
单位 Unit3。
interface
uses Generics.Collections;

type
  IXList<T> = interface
  end;

  TXList<T: class> = class(TList<T>, IXList<T>)
  protected
    FRefCount: Integer;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
    function Find: IXList<T>;
    function FindAll<S>: IXList<S>;
  end;

implementation
uses Windows;

function TXList<T>.Find: IXList<T>;
begin
  Result := TXList<T>.Create;
end;

function TXList<T>.FindAll<S>: IXList<S>;
begin
  Result := TXList<S>.Create; // Error here  
end;

function TXList<T>.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  Result := E_NoInterface;
end;

function TXList<T>._AddRef: Integer;
begin
  InterlockedIncrement(FRefCount);
end;

function TXList<T>._Release: Integer;
begin
  InterlockedDecrement(FRefCount);
  if FRefCount = 0 then Self.Destroy;
end;

end.

感谢您的回答!看起来是编译器错误,但有一个可接受的解决方法可用。
接口声明如下:
IXList<T: class> = interface
   function GetEnumerator: TList<T>.TEnumerator;
end;

"findall"的实现方式是什么?
function TXList<T>.FindAll<S>: IXList<S>;
var
  lst: TXList<S>;
  i: T;
begin
  lst := TXList<S>.Create;
  for i in Self do
    if i.InheritsFrom(S) then lst.Add(S(TObject(i)));

  Result := IXList<S>(IUnknown(lst));
end;

我在一个简单的示例中让它工作了。
做类似这样的事情:
var
  l: TXList<TAClass>;
  i: TASubclassOfTAClass;
begin
.
.
.
for i in l.FindAll<TASubclassOfTAClass> do
begin
   // Do something with i
end;
2个回答

5

通过三个小修改(IInterface,FindAll中的“S:class”[感谢Mason]和FindAll中的类型转换),我得到了编译结果。

完整代码:

unit Unit16;

interface

uses
  Generics.Collections;

type
  IXList<T> = interface
  end;

  TXList<T: class> = class(TList<T>, IInterface, IXList<T>)
  protected
    FRefCount: Integer;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
    function Find: IXList<T>;
    function FindAll<S: class>: IXList<S>;
  end;

implementation
uses Windows;

function TXList<T>.Find: IXList<T>;
begin
  Result := TXList<T>.Create;
end;

function TXList<T>.FindAll<S>: IXList<S>;
begin
  Result := IXList<S>(IUnknown(TXList<S>.Create));
end;

function TXList<T>.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  Result := E_NoInterface;
end;

function TXList<T>._AddRef: Integer;
begin
  InterlockedIncrement(FRefCount);
end;

function TXList<T>._Release: Integer;
begin
  InterlockedDecrement(FRefCount);
  if FRefCount = 0 then Self.Destroy;
end;

end.

不错,诀窍似乎是在类声明中明确命名IInterface。谢谢。 - PeterS

3
那绝对像是编译器错误。他们说他们已经花了很多精力来改进下一个版本,Delphi XE的泛型问题。当它发布时,应该会在接下来的几周内下载预览版,看看是否可以编译。如果不能,请尝试向QC提交错误报告。
此外,FindAll<S>可能应该声明为function FindAll<S: class>: IXList<S>;。这并不能解决错误,但工作正常的编译器可能会给您一个错误。

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