使用通用接口错误重载调用

时间:2015-02-11 19:07:43

标签: delphi delphi-xe2

假设我有这个定义:

TMyClass1 = class
end;

TMyClass2 = class
end;

IModel<T : class> = interface
  ['{E8262D6C-DCAB-46AC-822E-EC369CF734F8}']
  function List() : TObjectList<T>;
end;

IPresenter<T : class> = interface
  ['{98FB7751-D75A-4C51-B55A-0E5FE68BE213}']
  function Retrieve() : TObjectList<T>;
end;

IView<T : class> = interface
  ['{59384CD6-30D6-4BD8-AB3D-7FCF4D1A8618}']
  procedure AssignPresenter(APresenter : IPresenter<T>);
end;

TModel<T : class> = class(TInterfacedObject, IModel<T>)
public
  function List() : TObjectList<T>; virtual; abstract;
end;

TPresenter<T : class> = class(TInterfacedObject, IPresenter<T>)
strict private
  { Private declarations }
  FModel : IModel<T>;
  FView : IView<T>;
public
  constructor Create(AView : IView<T>);
  function Retrieve() : TObjectList<T>; virtual; abstract;
end;

TModelClass1 = class(TModel<TMyClass1>);

TPresenterClass1 = class(TPresenter<TMyClass1>);

TModelClass2 = class(TModel<TMyClass2>);

TPresenterClass2 = class(TPresenter<TMyClass2>);

我有这个表单来实现我定义的一些东西:

TForm1 = class(TForm, IView<TMyClass1>, IView<TMyClass2>)
  procedure FormCreate(Sender: TObject);
private
  { Private declarations }
  FPresenter1 : IPresenter<TMyClass1>;
  FPresenter2 : IPresenter<TMyClass2>;
  procedure AssignPresenter(APresenter : IPresenter<TMyClass1>); overload;
  procedure AssignPresenter(APresenter : IPresenter<TMyClass2>); overload;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 TPresenterClass1.Create((Self as IView<TMyClass1>));
 TPresenterClass2.Create((Self as IView<TMyClass2>));
end;

procedure TForm1.AssignPresenter(APresenter: IPresenter<TMyClass1>);
begin
  Self.FPresenter1 := APresenter;
end;

procedure TForm1.AssignPresenter(APresenter: IPresenter<TMyClass2>);
begin
  Self.FPresenter2 := APresenter;
end;

所以这里的问题是delphi无法找出要调用的方法,在这个例子中,在这两种情况下只调用了AssignPresenter(APresenter: IPresenter<TMyClass2>),所以可能我在这里遗漏了一些东西,但我可以&#39 ;弄清楚atm。

提前thx。

3 个答案:

答案 0 :(得分:3)

这可能是重复但我现在找不到它。

问题是接口的as运算符与泛型不兼容。 as运算符依赖于接口GUID。通过查询具有匹配GUID的接口找到该接口。并且GUID在通用实例化方面并不适合。

现在让我们来看看你的代码。

TPresenterClass1.Create((Self as IView<TMyClass1>));
TPresenterClass2.Create((Self as IView<TMyClass2>));

问题是IView<TMyClass1>IView<TMyClass2>具有相同的GUID:

type
  IView<T : class> = interface
    ['{59384CD6-30D6-4BD8-AB3D-7FCF4D1A8618}']
    procedure AssignPresenter(APresenter : IPresenter<T>);
  end;

因此,IView<TMyClass1>IView<TMyClass2>共享相同的GUID,当您使用as进行查询时,无论您是否要求IView<TMyClass1>,都会返回相同的界面}或IView<TMyClass2>

因此,这里的底线是,只要对象使用不同的as实现ISomeInterface<T>两次,T就会在通用接口旁边呈现无效。

Embarcadero确实应该以支持泛型的方式实现as。我不会屏住呼吸。

您需要找到一种不同的方法来解决您的问题。

答案 1 :(得分:2)

当你拥有实现接口的对象时,不需要使用as - 只需写:

procedure TForm1.FormCreate(Sender: TObject);
begin
  TPresenterClass1.Create(Self);
  TPresenterClass2.Create(Self);
end;

编译器正确地计算出来。当您使用as时,它会进行Supports调用,但由于David已解释的原因而失败。

答案 2 :(得分:0)

作为David Heffernan回答的补充。

解决问题的一种方法是为您使用的所有通用声明提供唯一的GUID:

IViewMyclass1 = interface(IView<TMyClass1>)
['{1A0F941F-BAB1-4723-A6C1-27036DF5D344}']
end;

IViewMyclass2 = interface(IView<TMyClass2>)
['{0C61A23A-DC50-43B0-97C9-8B0013DDC193}']
end;

重新定义视图的声明。

TForm4 = class(TForm, IViewMyclass1, IViewMyclass2)

procedure TForm1.FormCreate(Sender: TObject);
begin
 TPresenterClass1.Create((Self as IViewMyclass1));
 TPresenterClass2.Create((Self as IViewMyclass2));
end;

然后调用正确的重载。

免责声明:

  • 这是On-The-Fly测试(XE4)的结果。可靠性未知。
  • 我知道这不太实际。
  • 可能不应该广泛使用,因为代码失败的地方不明显。
相关问题