gpt4 book ai didi

delphi - 如何实现IEnumerable

转载 作者:行者123 更新时间:2023-12-03 14:35:58 27 4
gpt4 key购买 nike

我如何实现IEnumerable<T>

背景

假设我有一个想要实现的类 IEnumerable<T> :

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

var
IEnumerable<TMouse> mices = TStackoverflow<TMouse>.Create;

我会有一个实现:

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

function TStackoverflow<T>.GetEnumerator: IEnumerator<T>;
begin
Result := {snip, not important here};
end;

现在,为了成为一名优秀的程序员,我将选择我的类(class)也支持 IEnumerable接口(interface):

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

{ IEnumerable }
function GetEnumerator: IEnumerator;
end;

function TStackoverflow<T>.GetEnumerator: IEnumerator<T>;
begin
Result := {snip, not important here};
end;

function TStackoverflow.GetEnumerator: IEnumerator;
begin
Result := {snip, not important here};
end;

那些知道这是怎么回事的人会知道实现 IEnumerable是一个转移注意力的话题;无论哪种方式都必须完成。

现在问题来了

该代码无法编译,因为:

function GetEnumerator: IEnumerator<T>;
function GetEnumerator: IEnumerator;

我有两个具有相同签名的方法(不是真正相同的签名,但足够相同以至于 Delphi 无法区分它们):

E2254 Overloaded procedure 'GetEnumerator' must be marked with the 'overload' directive

好的,好的,我将它们标记为 overloads :

function GetEnumerator: IEnumerator<T>; overload;
function GetEnumerator: IEnumerator; overload;

但这不起作用:

E2252 Method 'GetEnumerator' with identical parameters already exists

接口(interface)方法解析

重载是错误的方法,我们应该寻找 method resolution clauses :

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 }

function TStackoverflow<T>.GetEnumeratorGeneric: IEnumerator;
begin

end;

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

end;

除了这也无法编译,原因我不明白:

E2291 Missing implementation of interface method IEnumerable.GetEnumerator

所以让我们忘记 IEnumerable

假装我不在乎我的类(class)是否不支持 IEnumerable ,让我们将其作为受支持的接口(interface)删除。它实际上并没有改变任何东西,如 IEnumerable<T>源自 IEnumerble :

IEnumerable<T> = interface(IEnumerable)
function GetEnumerator: IEnumerator<T>;
end;

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

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;

由于同样的原因无法编译:

E2291 Missing implementation of interface method IEnumerable.GetEnumerator

好吧,忘记泛型

所以,让我们停下来,合作并倾听。 IEnumerable 作为一项古老的新发明又回来了:

type
TStackoverflow = class(TInterfacedObject, IEnumerable)
public
function GetEnumerator: IEnumerator;
end;

{ TStackoverflow }

function TStackoverflow.GetEnumerator: IEnumerator;
begin

end;

非常好,有效。我可以获得类(class)支持IEnumerable 。现在我想支持IEnumerable<T> .

这引出了我的问题:

How to implement IEnumerable<T>?

<小时/>

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

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.

最佳答案

一个method resolution clause可以完成这项工作:

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;

您的尝试似乎失败了,因为您的方法都没有被命名为 GetEnumerator 。在我上面的代码中,其中之一称为 GetEnumerator另一个有不同的名字。根据我的实验,您必须拥有与接口(interface)方法同名的实现方法之一。

这很奇怪。我想说这看起来像是一个编译器错误。该行为甚至持续到 XE7。

另一方面,至少你现在有了前进的道路。

更新

好吧,Stefan 下面的评论让我终于明白到底发生了什么。这里实际上需要满足三个接口(interface)方法。显然我们必须提供 IEnumerable.GetEnumerator 的实现,以满足IEnumerable 。但自从 IEnumerable<T>源自IEnumerable ,然后IEnumerable<T>包含两个方法,IEnumerable.GetEnumeratorIEnumerable<T>.GetEnumerator 。所以你真正想要做的是这样的:

我发现跟踪冲突的名称和泛型有点困难,因此我将提供一个替代示例,我认为该示例更清楚地阐明了关键点:

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;

现在,请注意,使用接口(interface)继承意味着 IDerived包含两个方法,FooBar .

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

E2291 Missing implementation of interface method IBase.Foo

这当然看起来很奇怪,因为方法解析子句确实处理了这个问题。嗯,不,方法解析处理 FooIBase 中声明,但不是 IDerived 中的那个这是继承的。

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

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

procedure Proc2;
procedure IDerived.Bar = Proc2;
end;

这足以让编译器高兴。我们现在已经提供了需要实现的所有三种方法的实现。

不幸的是,您无法使用 IEnumerable<T> 执行此操作因为继承的方法与 IEnumerable<T> 引入的新方法同名.

再次感谢Stefan带领我启蒙。

关于delphi - 如何实现IEnumerable<T>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26549983/

27 4 0