如何正确使接口支持迭代? [英] How to properly make an interface support iteration?

查看:153
本文介绍了如何正确使接口支持迭代?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何从界面公开此TList,如 IEnumerator IEnumerator< IFungibleTroll> ?我正在使用Delphi XE。



这是我有多远:

 单位FungibleTrollUnit; 

接口

使用
Windows,消息,SysUtils,
变体,类,图形,
控件,表单,
泛型

type
IFungibleTroll = interface
['{03536137-E3F7-4F9B-B1F5-2C8010A4D019}']
函数GetTrollName:String;
函数GetTrollRetailPrice:Double;
结束


TFungibleTrolls = class(TInterfacedObject,IEnumerable< IFungibleTroll>)
protected
FTrolls:TList< IFungibleTroll> ;;

public
// IEnumerable
函数GetEnumerator:IEnumerator< IFungibleTroll> ;; //
//函数GetEnumerator:IEnumerator;超载;

//查找/搜索应用功能需要搜索。
//这个

函数FindSingleItemByName(aName:String; patternMatch:Boolean):IFungibleTroll;
函数FindMultipleItemsByName(aName:String; patternMatch:Boolean):IEnumerable< IFungibleTroll> ;;
函数FindSingleItemByIdentifier(anIdentifer:String):IFungibleTroll; //使用内部非可见标识符来查找应用程序。

构造函数创建;

属性巨魔:TList< IFungibleTroll>阅读FTrolls // implements IEnumerable< IFungibleTroll> ;;?
private
end;




实现


{TFungibleTrolls}

构造函数TFungibleTrolls.Create;
begin
FTrolls:= TList< IFungibleTroll> .Create;

end;

函数TFungibleTrolls.FindMultipleItemsByName(aName:String;
patternMatch:Boolean):IEnumerable< IFungibleTroll> ;;
begin

end;

函数TFungibleTrolls.FindSingleItemByIdentifier(
anIdentifer:String):IFungibleTroll;
begin

end;

函数TFungibleTrolls.FindSingleItemByName(aName:String;
patternMatch:Boolean):IFungibleTroll;
begin

end;



函数TFungibleTrolls.GetEnumerator:IEnumerator< IFungibleTroll> ;;
begin
result:= FTrolls.GetEnumerator;
结束

//函数TFungibleTrolls.GetEnumerator:IEnumerator;
// begin
// result:= FTrolls.GetEnumerator; // type IEnumerator< IFungibleTroll>或IEnumerator?
// end;


结束。

我陷入了三个错误之一,我无法弄清楚如何解决: p>

[DCC错误] FungibleTrollUnit.pas(26):E2252具有相同参数的方法GetEnumerator已存在
-or -



[DCC错误] FungibleTrollUnit.pas(19):E2291缺少接口方法的实现IEnumerable.GetEnumerator
-or-
[DCC错误] FungibleTrollUnit.pas(19):E2291缺少接口方法的实现IEnumerable.GetEnumerator



似乎我必须声明两种形式的GetEnumerator,如果我声明TFungibleTrolls实现IEnumerable,但我似乎无法弄清楚如何做,无论是重载或没有重载,或使用方法解析条款,如下所示:

  function IEnumerable.GetEnumerator = GetPlainEnumerator; //需要方法解析条款? 
函数GetEnumerator:IEnumerator< IFungibleTroll> ;;
函数GetPlainEnumerator:IEnumerator;

这可能看起来像是一个非常基本的使用IEnumerable,并使接口支持迭代,我被卡住了。



更新:在没有首先声明 List< T> ,由于 IEnumerable< T> 继承自 IEnumerable 的事实,我陷入了一个裂缝,但是,我的类不是单个获取枚举器方法,而是提供多个类,而且由于我的类不是通用的,所以它不能直接映射到IEnumerable的要求,除非我使用通用的列表< T> 声明。当编译成一个项目(.dproj + .dpr),而不是内置到一个包(.dproj + .dpk)并在IDE中编译时,Marjan的示例可以工作。它可以从命令行,一个包中,而不是在IDE中,在一个包中。

解决方案

不直接回答你的问题(仍然在工作),但这是我做了一个接口枚举器,即接口类支持迭代:

  IList< T> = interface(IInterface)
[...]
函数GetEnumerator:TList< T> .TEnumerator;
function Add(const Value:T):Integer;
结束

type
TBjmInterfacedList< T> = class(TBjmInterfacedObject,IList< T)
strict private
FList:TList< T>;
函数GetEnumerator:TList< T> .TEnumerator;
strict protected
function Add(const Value:T):Integer;
public
构造函数创建;覆盖
析构函数覆盖
结束

实现

构造函数TBjmInterfacedList< T>创建;
开始
继承;
FList:= TList< T>。创建;
结束

析构函数TBjmInterfacedList< T> .Destroy;
begin
FreeAndNil(FList);
继承;
结束

函数TBjmInterfacedList< T> .GetEnumerator:TList< T> .TEnumerator;
begin
结果:= FList.GetEnumerator;
结束

函数TBjmInterfacedList< T> .Add(const Value:T):整数;
begin
结果:= FList.Add(Value);
结束

然后,您可以执行以下操作:

  ISite = interface(IInterface)
...
end;
ISites = interface(IList< ISite>);
...
end;

var
网站中的网站开始
...
end;

与实现类,如:

  TSite = class(TBjmInterfacedObject,ISite)
...
end;
TSites = class(TBjmInterfacedList< ISite>,ISites)
...
end;

更新



示例项目源上传到
http://www.bjmsoftware.com/ delphistuff / stackoverflow / interfacedlist.zip


How can I expose this TList from an interface, as either IEnumerator or IEnumerator<IFungibleTroll>? I am using Delphi XE.

Here's how far I got:

unit FungibleTrollUnit;

interface

uses
  Windows, Messages, SysUtils,
  Variants, Classes, Graphics,
  Controls, Forms,
  Generics.Collections;

type
  IFungibleTroll = interface
    ['{03536137-E3F7-4F9B-B1F5-2C8010A4D019}']
       function GetTrollName:String;
       function GetTrollRetailPrice:Double;
  end;


  TFungibleTrolls = class (TInterfacedObject,IEnumerable<IFungibleTroll>)
      protected
         FTrolls:TList<IFungibleTroll>;

      public
          // IEnumerable
          function GetEnumerator:IEnumerator<IFungibleTroll>;//
//          function GetEnumerator:IEnumerator; overload;

         // find/search app feature requires searching.
         // this

         function FindSingleItemByName(aName:String;patternMatch:Boolean):IFungibleTroll;
         function FindMultipleItemsByName(aName:String;patternMatch:Boolean):IEnumerable<IFungibleTroll>;
         function FindSingleItemByIdentifier(anIdentifer:String):IFungibleTroll;// use internal non-visible identifier to find an app.

         constructor Create;

         property Trolls:TList<IFungibleTroll> read FTrolls; // implements IEnumerable<IFungibleTroll>;??
  private
  end;




implementation


{ TFungibleTrolls }

constructor TFungibleTrolls.Create;
begin
         FTrolls := TList<IFungibleTroll>.Create;

end;

function TFungibleTrolls.FindMultipleItemsByName(aName: String;
  patternMatch: Boolean): IEnumerable<IFungibleTroll>;
begin

end;

function TFungibleTrolls.FindSingleItemByIdentifier(
  anIdentifer: String): IFungibleTroll;
begin

end;

function TFungibleTrolls.FindSingleItemByName(aName: String;
  patternMatch: Boolean): IFungibleTroll;
begin

end;



function TFungibleTrolls.GetEnumerator: IEnumerator<IFungibleTroll>;
begin
  result := FTrolls.GetEnumerator;
end;

//function TFungibleTrolls.GetEnumerator: IEnumerator;
//begin
//  result := FTrolls.GetEnumerator; // type IEnumerator<IFungibleTroll> or IEnumerator?
//end;


end.

I get stuck in one of three errors that I can't figure out how to solve:

[DCC Error] FungibleTrollUnit.pas(26): E2252 Method 'GetEnumerator' with identical parameters already exists -or-

[DCC Error] FungibleTrollUnit.pas(19): E2291 Missing implementation of interface method IEnumerable.GetEnumerator -or- [DCC Error] FungibleTrollUnit.pas(19): E2291 Missing implementation of interface method IEnumerable.GetEnumerator

It seems I must declare two forms of GetEnumerator, if I declare TFungibleTrolls to implement IEnumerable, but I can't seem to figure out how to do it, either with overloads, or without overloads, or using a "method resolution clause", like this:

      function IEnumerable.GetEnumerator = GetPlainEnumerator; // method resolution clause needed?
      function GetEnumerator:IEnumerator<IFungibleTroll>;
      function GetPlainEnumerator:IEnumerator;

This probably seems like a pretty basic use of IEnumerable, and making an Interface support iteration, and yet, I'm stuck.

Update: It seems when I try to do this without first declaring a List<T>, I am falling into a crack caused by the fact that IEnumerable<T> inherits from IEnumerable, and yet, instead of a single get enumerator method, my class must provide multiple ones, and because my class is not a generic, it can't "map itself" to IEnumerable's requirements directly unless I use a generic List<T> declaration. Marjan's sample works, when compiled into a project (.dproj+.dpr) but not when built into a package (.dproj+.dpk) and compiled in the IDE. It works fine from the command line, in a package, but not in the IDE, in a package.

解决方案

Not an answer to your question directly (still working on that), but this is what I did to get an "interfaced enumerator", ie and interfaced class that supports iteration:

IList<T> = interface(IInterface)
  [...]
  function GetEnumerator: TList<T>.TEnumerator;
  function Add(const Value: T): Integer;
end;

type
  TBjmInterfacedList<T> = class(TBjmInterfacedObject, IList<T>)
  strict private
    FList: TList<T>;
    function GetEnumerator: TList<T>.TEnumerator;
  strict protected
    function Add(const Value: T): Integer;
  public
    constructor Create; override;
    destructor Destroy; override;
  end;

implementation

constructor TBjmInterfacedList<T>.Create;
begin
  inherited;
  FList := TList<T>.Create;
end;

destructor TBjmInterfacedList<T>.Destroy;
begin
  FreeAndNil(FList);
  inherited;
end;

function TBjmInterfacedList<T>.GetEnumerator: TList<T>.TEnumerator;
begin
  Result := FList.GetEnumerator;
end;

function TBjmInterfacedList<T>.Add(const Value: T): Integer;
begin
  Result := FList.Add(Value);
end;

And then you can do stuff like:

ISite = interface(IInterface)
  ...
end;
ISites = interface(IList<ISite>);
  ...
end;

var
  for Site in Sites do begin
    ...
  end;

with implementing classes like:

TSite = class(TBjmInterfacedObject, ISite)
  ...
end;
TSites = class(TBjmInterfacedList<ISite>, ISites)
  ...
end;

Update

Example project source uploaded to http://www.bjmsoftware.com/delphistuff/stackoverflow/interfacedlist.zip

这篇关于如何正确使接口支持迭代?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆