繁体   English   中英

类型X的参数必须支持接口Y.

[英]Parameter of type X must support interface Y

我有这样的设置:

IBuilder = interface(IInvokable)
end;

IBuilder<T: IBuilder; TOut : TWinControl> = interface(IInvokable)
end;

TBuilder<T: IBuilder; TOut : TWinControl> = class(TInterfacedObject, IBuilder, IBuilder<T, TOut>)
end;

TBuilder = class(TBuilder<TBuilder, TWinControl>)
end;

这种结构允许我像这样构建一个糖语法:

TBuilder<T : IBuilder; TOut : TWinControl> = class(TInterfacedObject, IBuilder, IBuilder<T, TOut>)

  function Output : TOut;
  function Name(aName : string) : T;
  function Left(aLeft : Integer) : T;
  function Top(aTop : Integer) : T;

end;

// ... later

TBuilder.Create().Left(10).Top(5).Name('ABC'); // Nice one liner

问题是我得到了编译错误,这样说

E2514 The type parameter TBuilder must support interface 'IBuilder'.

这可能是由于接口上存在类型约束T: IBuilder ,即使TBuilder确实支持IBuilder(通过它的祖先)。

任何人都可以指导我如何解决这个问题?

虽然,我不能使用TBuilder = class(TBuilder<IBuilder, TObject>)

这是不可能做到的。 你基本上是想这样做:

  IBar = interface(IInterface) end; 

  TFoo<T : IBar> = class(TObject, IBar) end;

  TBar = TFoo<TBar>;

哪会产生错误

E2086型'TBar'尚未完全定义

如果没有接口依赖性,您可以将其写为

 TBar = class(TFoo<TBar>) end;

使它成为一个真正的后代,而不仅仅是一个别名。 这通常可以解析类型,但是接口依赖性迫使编译器提出问题: TBar是否支持IBar

如果你考虑一下,这就是:

TBar = TFoo<TBar>   {TBar support IBar?}  
             |
             TBar = TFoo<TBar>... {ok, TBar support IBar?}
                          |
                         TBar = TFoo<TBar> {ok, TBar support IBar?}
                                      |
                                      {...turtles all the way down}

您要求编译器解决无限递归问题。 它无法做到这一点。

您可以通过更改方法的返回类型并排除递归类型参数来解决此问题。

interface
type
  //IBuilder = interface(IInvokable)
  //end;  //I don't think you need this

  IBuilder<TOut : TWinControl> = interface(IInvokable)
    function Output : TOut;
    function Name(const aName : string) : IBuilder<TOut>;
    function Left(aLeft : Integer) : IBuilder<TOut>;
    function Top(aTop : Integer) : IBuilder<TOut>;
  end;

 TFactory<TOut: TWinControl> = record
   class function New: IBuilder<TOut>; static;
 end;

implementation
type    
  //Put the actual class in the implementation
  TBuilder<TOut : TWinControl> = class(TInterfacedObject, IBuilder<TOut>)
     //see interface
  end;

你通常这样使用它:

var 
  MyButton: IBuilder<TButton>;
begin  
  MyButton:= TFactory<TButton>.New.Left(10).Top(5).Name('ABC');

如果您正在使用接口,那么您永远不应该使用该类,始终只与该接口进行交互。 通过在实现中移动类定义,您可以强制执行此操作。 为了补偿您在界面中添加工厂方法。

在这种情况下,它必须是一个记录,因为你不能(还)拥有通用的独立方法。

class function TFactory<TOut>.New: IBuilder<TOut>;
begin
  Result:= TBuilder<TOut>.Create;
end;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM