Delphi 如何实现IEnumerable<;T>;?

Delphi 如何实现IEnumerable<;T>;?,delphi,generics,delphi-xe6,Delphi,Generics,Delphi Xe6,如何实现IEnumerable 背景 假设我有一个类要实现IEnumerable: IEnumerable<T> = interface(IEnumerable) function GetEnumerator: IEnumerator<T>; end; type TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>) protected func

如何实现
IEnumerable

背景 假设我有一个类要实现
IEnumerable

IEnumerable<T> = interface(IEnumerable)
  function GetEnumerator: IEnumerator<T>;
end;
type
    TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>)
    protected
        function GetEnumeratorTyped: IEnumerator<T>;
    public
        function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
    end;

{ TStackoverflow }

function TStackoverflow<T>.GetEnumeratorTyped: IEnumerator<T>;
begin

end;
知道这一点的人都会知道,实现
IEnumerable
是一件麻烦事;无论哪种方式都必须这样做

现在问题来了 该代码无法编译,因为:

function GetEnumerator: IEnumerator<T>;
function GetEnumerator: IEnumerator;
但这不起作用:

E2252具有相同参数的方法“GetEnumerator”已存在

界面方法分辨率 过载是错误的方法,我们应该注意:

因此,该方法必须存在,并且删除
IEnumerable
的代码必须存在:

IEnumerable<T> = interface(IEnumerable)
  function GetEnumerator: IEnumerator<T>;
end;
type
    TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>)
    protected
        function GetEnumeratorTyped: IEnumerator<T>;
    public
        function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
    end;

{ TStackoverflow }

function TStackoverflow<T>.GetEnumeratorTyped: IEnumerator<T>;
begin

end;
太好了,这很有效。我可以让我的类支持
IEnumerable
。现在我想支持
IEnumerable

这就引出了我的问题:


更新:忘记附加完整的非功能代码:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
    TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>, IEnumerable)
    protected
        function GetEnumeratorTyped: IEnumerator<T>;
        function GetEnumeratorGeneric: IEnumerator;
    public
        function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
        function IEnumerable.GetEnumerator = GetEnumeratorGeneric;
    end;

{ TStackoverflow<T> }

function TStackoverflow<T>.GetEnumeratorGeneric: IEnumerator;
begin

end;

function TStackoverflow<T>.GetEnumeratorTyped: IEnumerator<T>;
begin

end;

begin
  try
     { TODO -oUser -cConsole Main : Insert code here }
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
程序项目1;
{$APPTYPE控制台}
{$R*.res}
使用
System.SysUtils;
类型
TStackoverflow=类(TInterfacedObject、IEnumerable、IEnumerable)
受保护的
函数GetEnumeratorTyped:IEnumerator;
函数GetEnumeratorGeneric:IEnumerator;
公众的
函数IEnumerable.GetEnumerator=GetEnumeratorTyped;
函数IEnumerable.GetEnumerator=GetEnumeratorGeneric;
结束;
{TStackoverflow}
函数TStackoverflow.GetEnumeratorGeneric:IEnumerator;
开始
结束;
函数TStackoverflow.GetEnumeratorTyped:IEnumerator;
开始
结束;
开始
尝试
{TODO-oUser-cConsole Main:在此处插入代码}
除了
关于E:Exception-do
Writeln(E.ClassName,“:”,E.Message);
结束;
结束。
A可以完成以下工作:

type
  TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>, IEnumerable)
  public
    { IEnumerable<T> }
    function GetEnumeratorGeneric: IEnumerator<T>;
    function IEnumerable<T>.GetEnumerator = GetEnumeratorGeneric;

    { IEnumerable }
    function GetEnumerator: IEnumerator;
    function IEnumerable.GetEnumerator = GetEnumerator;
  end;
现在,请注意,使用接口继承意味着
IDerived
包含两种方法,
Foo
Bar

上面的代码无法编译。编者说:

E2291缺少接口方法IBase.Foo的实现

这当然看起来很奇怪,因为方法解决条款肯定处理了这个问题。不,方法解析处理的是
IBase
中声明的
Foo
,而不是继承的
IDerived
中声明的
Foo

在上面的例子中,我们可以很容易地解决问题:

TImplementingClass = class(TInterfacedObject, IBase, IDerived)
  procedure Proc1;
  procedure IBase.Foo = Proc1;
  procedure IDerived.Foo = Proc1;

  procedure Proc2;
  procedure IDerived.Bar = Proc2;
end;
这足以让编译器感到高兴。我们现在已经为所有需要实现的三种方法提供了实现

不幸的是,您无法使用
IEnumerable
执行此操作,因为继承的方法与
IEnumerable
引入的新方法具有相同的名称


再次感谢Stefan带领我走向启蒙。

快速简短回答

有两个名称相同的接口组,例如:非通用的
IEnumerable
和:
IEnumerable

概述

我也有同样的问题

问题不是接口实现,也不是通用接口实现

IEnumerable
这样的通用接口有一种特殊情况,因为它们也有一个非通用的
IEnumerable
接口。这个接口是为了与O.S.兼容,它们不仅仅是另一个编程接口

此外,还有一些其他通用和非通用父接口,如
IEnumerator
IComparable
,它们有自己的成员定义

解决方案

为了解决同样的问题,我会查找
IEnumerable
有哪些父接口,并检测匹配的非泛型接口

以及,添加和中间实现非泛型接口的非泛型类。这使我能够轻松地检测缺少哪些接口和匹配的成员定义

type
    // Important: This intermediate class declaration is NOT generic

    // Verify that non generic interface members implemented

    TStackoverflowBase = class(TInterfacedObject, IEnumerable)
    protected
        function GetEnumeratorGeneric: IEnumerator;
    public
        function IEnumerable.GetEnumerator = GetEnumeratorGeneric;
    end;

    // Important: This proposed class declaration IS generic,
    // yet, it descends from a non generic intermediate class.

    // After verify that non generic interface members implemented,
    // verify that generic interface members implemented,

    TStackoverflow<T> = class(TStackoverflowBase, IEnumerable<T>)
    protected
        function GetEnumeratorTyped: IEnumerator<T>;
    public
        function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
    end;
类型
//要点:此中间类声明不是泛型的
//验证是否实现了非通用接口成员
TStackoverflowBase=class(TInterfacedObject,IEnumerable)
受保护的
函数GetEnumeratorGeneric:IEnumerator;
公众的
函数IEnumerable.GetEnumerator=GetEnumeratorGeneric;
结束;
//要点:此建议的类声明是泛型的,
//然而,它来自一个非泛型的中间类。
//在验证是否实现了非通用接口成员之后,
//验证是否实现了通用接口成员,
TStackoverflow=类(TStackoverflowBase,IEnumerable)
受保护的
函数GetEnumeratorTyped:IEnumerator;
公众的
函数IEnumerable.GetEnumerator=GetEnumeratorTyped;
结束;
事情就更难了,因为有几个成员重载了相同的标识符,但参数类型或返回类型不同, 取决于,它们是来自通用接口还是来自非通用接口

@davidheffernan的解决方案只有一个类,这并不坏,我也尝试过同样的方法,但更复杂

因此,我应用了中间类,因为它允许我找出缺少哪些接口和相应的成员

type
    // Important: This intermediate class declaration is NOT generic

    // Verify that non generic interface members implemented

    TStackoverflowBase = class(TInterfacedObject, IEnumerable)
    protected
        function GetEnumeratorGeneric: IEnumerator;
    public
        function IEnumerable.GetEnumerator = GetEnumeratorGeneric;
    end;

    // Important: This proposed class declaration IS generic,
    // yet, it descends from a non generic intermediate class.

    // After verify that non generic interface members implemented,
    // verify that generic interface members implemented,

    TStackoverflow<T> = class(TStackoverflowBase, IEnumerable<T>)
    protected
        function GetEnumeratorTyped: IEnumerator<T>;
    public
        function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
    end;

干杯。

事实上,这很简单,虽然不是很明显。关键是要知道编译器对枚举数有一些魔力

首先,我们根本不需要实现
IEnumerator
IEnumerator
。相反,我们声明或拥有接口。对于这个示例,我们正在枚举WideString,因此它可能如下所示。请注意,方法/属性名称和签名在此处很重要:

IFoobarEnumerator = interface
  function GetCurrent: WideString;
  function MoveNext: Boolean;
  procedure Reset;
  property Current: WideString read GetCurrent;
end;
现在,周围的类获得一个名为
GetEnumerator
的方法,该方法返回类似于枚举器的内容

我特意写了“看起来像枚举器的东西”,而不是“实现
IEnumerator
”的东西,因为这就是编译器实现奇迹所需要的一切:

type IBase = interface procedure Foo; end; IDerived = interface(IBase) procedure Bar; end; TImplementingClass = class(TInterfacedObject, IBase, IDerived) procedure Proc1; procedure IBase.Foo = Proc1; procedure Proc2; procedure IDerived.Bar = Proc2; end;
TImplementingClass = class(TInterfacedObject, IBase, IDerived)
  procedure Proc1;
  procedure IBase.Foo = Proc1;
  procedure IDerived.Foo = Proc1;

  procedure Proc2;
  procedure IDerived.Bar = Proc2;
end;
type
    // Important: This intermediate class declaration is NOT generic

    // Verify that non generic interface members implemented

    TStackoverflowBase = class(TInterfacedObject, IEnumerable)
    protected
        function GetEnumeratorGeneric: IEnumerator;
    public
        function IEnumerable.GetEnumerator = GetEnumeratorGeneric;
    end;

    // Important: This proposed class declaration IS generic,
    // yet, it descends from a non generic intermediate class.

    // After verify that non generic interface members implemented,
    // verify that generic interface members implemented,

    TStackoverflow<T> = class(TStackoverflowBase, IEnumerable<T>)
    protected
        function GetEnumeratorTyped: IEnumerator<T>;
    public
        function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
    end;
IFoobarEnumerator = interface
  function GetCurrent: WideString;
  function MoveNext: Boolean;
  procedure Reset;
  property Current: WideString read GetCurrent;
end;
function  GetEnumerator : IFoobarEnumerator;