![](/img/trans.png)
[英]TYPESCRIPT : Argument of type 'typeof X' is not assignable to parameter of type 'Y' with extends
[英]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.