簡體   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