delphi – 如何实现IEnumerable?

前端之家收集整理的这篇文章主要介绍了delphi – 如何实现IEnumerable?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
如何实现IEnumerable< T>?

背景

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

  1. TStackoverflow<T> = class(TInterfacedObject,IEnumerable<T>)
  2. public
  3. { IEnumerable<T> }
  4. function GetEnumerator: IEnumerator<T>;
  5. end;
  6.  
  7. var
  8. IEnumerable<TMouse> mices = TStackoverflow<TMouse>.Create;

我会有一个实现:

  1. TStackoverflow<T> = class(TInterfacedObject,IEnumerable<T>)
  2. public
  3. { IEnumerable<T> }
  4. function GetEnumerator: IEnumerator<T>;
  5. end;
  6.  
  7. function TStackoverflow<T>.GetEnumerator: IEnumerator<T>;
  8. begin
  9. Result := {snip,not important here};
  10. end;

现在,为了成为一名好的程序员,我会选择我的类也将支持IEnumerable接口:

  1. TStackoverflow<T> = class(TInterfacedObject,IEnumerable<T>,IEnumerable)
  2. public
  3. { IEnumerable<T> }
  4. function GetEnumerator: IEnumerator<T>;
  5.  
  6. { IEnumerable }
  7. function GetEnumerator: IEnumerator;
  8. end;
  9.  
  10. function TStackoverflow<T>.GetEnumerator: IEnumerator<T>;
  11. begin
  12. Result := {snip,not important here};
  13. end;
  14.  
  15. function TStackoverflow.GetEnumerator: IEnumerator;
  16. begin
  17. Result := {snip,not important here};
  18. end;

那些知道这个事情的人会知道实现IEnumerable是一个红鲱鱼;不得不做任何一种方式.

现在问题了

代码不编译,因为:

  1. function GetEnumerator: IEnumerator<T>;
  2. function GetEnumerator: IEnumerator;

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

E2254 Overloaded procedure ‘GetEnumerator’ must be marked with the ‘overload’ directive

好的,我会把它们标记为超载:

  1. function GetEnumerator: IEnumerator<T>; overload;
  2. function GetEnumerator: IEnumerator; overload;

但这不行:

E2252 Method ‘GetEnumerator’ with identical parameters already exists

界面方法分辨率

超载是错误的做法,我们应该期待method resolution clauses

  1. type
  2. TStackoverflow<T> = class(TInterfacedObject,IEnumerable)
  3. protected
  4. function GetEnumeratorTyped: IEnumerator<T>;
  5. function GetEnumeratorGeneric: IEnumerator;
  6. public
  7. function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
  8. function IEnumerable.GetEnumerator = GetEnumeratorGeneric;
  9. end;
  10.  
  11. { TStackoverflow }
  12.  
  13. function TStackoverflow<T>.GetEnumeratorGeneric: IEnumerator;
  14. begin
  15.  
  16. end;
  17.  
  18. function TStackoverflow<T>.GetEnumeratorTyped: IEnumerator<T>;
  19. begin
  20.  
  21. end;

除此之外,还没有编译,因为逃避我的原因:

E2291 Missing implementation of interface method IEnumerable.GetEnumerator

所以让我们忘记IEnumerable

假装我不在乎我的课堂是否不支持IEnumerable,可以将其删除支持的界面.它实际上并不改变任何东西,因为IEnumerable< T>从IEnumerble下降:

  1. IEnumerable<T> = interface(IEnumerable)
  2. function GetEnumerator: IEnumerator<T>;
  3. end;

所以方法必须存在,而删除IEnumerable的代码

  1. type
  2. TStackoverflow<T> = class(TInterfacedObject,IEnumerable<T>)
  3. protected
  4. function GetEnumeratorTyped: IEnumerator<T>;
  5. public
  6. function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
  7. end;
  8.  
  9. { TStackoverflow }
  10.  
  11. function TStackoverflow<T>.GetEnumeratorTyped: IEnumerator<T>;
  12. begin
  13.  
  14. end;

不会因为同样的原因编译:

E2291 Missing implementation of interface method IEnumerable.GetEnumerator

那好吧,忘了仿制药

所以让我们停止,协作和听. IEnumerable是一个旧的新发明:

  1. type
  2. TStackoverflow = class(TInterfacedObject,IEnumerable)
  3. public
  4. function GetEnumerator: IEnumerator;
  5. end;
  6.  
  7. { TStackoverflow }
  8.  
  9. function TStackoverflow.GetEnumerator: IEnumerator;
  10. begin
  11.  
  12. end;

优秀的,有效的我可以让我的班级支持IEnumerable.现在我想支持IEnumerable< T>.

这导致我的问题:

07001

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

  1. program Project1;
  2.  
  3. {$APPTYPE CONSOLE}
  4.  
  5. {$R *.res}
  6.  
  7. uses
  8. System.SysUtils;
  9.  
  10. type
  11. TStackoverflow<T> = class(TInterfacedObject,IEnumerable)
  12. protected
  13. function GetEnumeratorTyped: IEnumerator<T>;
  14. function GetEnumeratorGeneric: IEnumerator;
  15. public
  16. function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
  17. function IEnumerable.GetEnumerator = GetEnumeratorGeneric;
  18. end;
  19.  
  20. { TStackoverflow<T> }
  21.  
  22. function TStackoverflow<T>.GetEnumeratorGeneric: IEnumerator;
  23. begin
  24.  
  25. end;
  26.  
  27. function TStackoverflow<T>.GetEnumeratorTyped: IEnumerator<T>;
  28. begin
  29.  
  30. end;
  31.  
  32. begin
  33. try
  34. { TODO -oUser -cConsole Main : Insert code here }
  35. except
  36. on E: Exception do
  37. Writeln(E.ClassName,': ',E.Message);
  38. end;
  39. end.

解决方法

method resolution clause可以做这个工作:
  1. type
  2. TStackoverflow<T> = class(TInterfacedObject,IEnumerable)
  3. public
  4. { IEnumerable<T> }
  5. function GetEnumeratorGeneric: IEnumerator<T>;
  6. function IEnumerable<T>.GetEnumerator = GetEnumeratorGeneric;
  7.  
  8. { IEnumerable }
  9. function GetEnumerator: IEnumerator;
  10. function IEnumerable.GetEnumerator = GetEnumerator;
  11. end;

您的尝试失败,似乎是因为您的方法都没有被命名为GetEnumerator.在我的代码中,其中一个被称为GetEnumerator,另一个被赋予一个不同的名字.从我的实验中,你必须有一个与接口方法具有相同名称实现方法.

哪个是奇怪的我会说这看起来像一个编译器的bug.行为仍然持续到XE7.

另一方面,至少你有一个方法可以向前迈进.

更新

好的,Stefan在下面的评论导致我迟来了解真正发生了什么.您实际上需要在这里满足三种接口方法.显然,我们必须为IEnumerable.GetEnumerator提供一个实现,以满足IEnumerable.但是由于IEnumerable< T>来自IEnumerable,然后IEnumerable< T>包含两种方法:IEnumerable.GetEnumerator和IEnumerable> .GetEnumerator.所以你真正想要做的就是这样:

我发现有一点很难跟踪冲突的名字和仿制药,所以我将提供一个替代例子,我认为更清楚地提出了关键点:

  1. type
  2. IBase = interface
  3. procedure Foo;
  4. end;
  5.  
  6. IDerived = interface(IBase)
  7. procedure Bar;
  8. end;
  9.  
  10. TImplementingClass = class(TInterfacedObject,IBase,IDerived)
  11. procedure Proc1;
  12. procedure IBase.Foo = Proc1;
  13.  
  14. procedure Proc2;
  15. procedure IDerived.Bar = Proc2;
  16. end;

现在,请注意,使用接口继承意味着IDerived包含两个方法Foo和Bar.

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

E2291 Missing implementation of interface method IBase.Foo

当然,这似乎是奇怪的,因为方法解决条款肯定是这样解决的.那么不,方法决议涉及到在IBase中声明的Foo,而不是继承的IDerived中的Foo.

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

  1. TImplementingClass = class(TInterfacedObject,IDerived)
  2. procedure Proc1;
  3. procedure IBase.Foo = Proc1;
  4. procedure IDerived.Foo = Proc1;
  5.  
  6. procedure Proc2;
  7. procedure IDerived.Bar = Proc2;
  8. end;

这足以使编译器快乐.我们现在为所有需要实现的三种方法提供了实现.

不幸的是,您无法使用IEnumerable< T>因为继承方法与IEnumerable< T>引入的新方法具有相同的名称.

再次感谢Stefan带领我启迪.

猜你在找的Delphi相关文章