我有一個實作通用介面的多個版本的物件。為避免混淆,我在課堂上使用了方法決議子句:https : //docwiki.embarcadero.com/RADStudio/Sydney/en/Implementing_Interfaces
假設我有一個多動物處理程式,可以處理貓和狗(無論這意味著什么)。處理程式IRequestHandler<TResponse, TRequest>為貓和狗實作了一個處理程式 ( ) 介面:
IRequestHandler<TResponse: record; TRequest: record> = Interface(IInvokable)
['{AFF8703B-F2AC-44D6-B82C-43E3492ADBB3}']
function Handle(ARequest: TRequest): TResponse;
End;
TCatRequest = record
end;
TCatResponse = record
end;
TDogRequest = record
end;
TDogResponse = record
end;
TMultiAnimalHandler=class(TInterfacedObject,
IRequestHandler<TCatResponse, TCatRequest>,
IRequestHandler<TDogResponse, TDogRequest>)
public
function IRequestHandler<TCatResponse, TCatRequest>.Handle = HandleCatRequest;
function HandleCatRequest(ARequest: TCatRequest): TCatResponse;
function IRequestHandler<TDogResponse, TDogRequest>.Handle = HandleDogRequest;
function HandleDogRequest(ARequest: TDogRequest): TDogResponse;
end;
問題是,當我嘗試對特定介面IRequestHandler<TCatResponse, TCatRequest>和進行型別轉換時IRequestHandler<TDogResponse, TDogRequest>,它并不總是決議為正確的方法。
完整示例:
type
IRequestHandler<TResponse: record; TRequest: record> = Interface(IInvokable)
['{AFF8703B-F2AC-44D6-B82C-43E3492ADBB3}']
function Handle(ARequest: TRequest): TResponse;
End;
TCatRequest = record
end;
TCatResponse = record
end;
TDogRequest = record
end;
TDogResponse = record
end;
TMultiAnimalHandler=class(TInterfacedObject,
IRequestHandler<TCatResponse, TCatRequest>,
IRequestHandler<TDogResponse, TDogRequest>)
public
function IRequestHandler<TCatResponse, TCatRequest>.Handle = HandleCatRequest;
function HandleCatRequest(ARequest: TCatRequest): TCatResponse;
function IRequestHandler<TDogResponse, TDogRequest>.Handle = HandleDogRequest;
function HandleDogRequest(ARequest: TDogRequest): TDogResponse;
end;
function TMultiAnimalHandler.HandleCatRequest(
ARequest: TCatRequest): TCatResponse;
begin
WriteLn('Miav!');
end;
function TMultiAnimalHandler.HandleDogRequest(
ARequest: TDogRequest): TDogResponse;
begin
WriteLn('Woof!');
end;
var
catHandler: IRequestHandler<TCatResponse, TCatRequest>;
dogHandler: IRequestHandler<TDogResponse, TDogRequest>;
multiAnimalHandler: TMultiAnimalHandler;
dogRequest: TDogRequest;
catRequest: TCatRequest;
begin
try
multiAnimalHandler := TMultiAnimalHandler.Create;
dogHandler := multiAnimalHandler;
catHandler := multiAnimalHandler;
// Works
dogHandler.Handle(dogRequest);
// Works
catHandler.Handle(catRequest);
// Works
(multiAnimalHandler as IRequestHandler<TDogResponse, TDogRequest>).Handle(dogRequest);
// Does not work. The Handle function calls HandleDogRequest, even if I cast multiAnimalHandler to IRequestHandler<TCatResponse, TCatRequest>!?
(multiAnimalHandler as IRequestHandler<TCatResponse, TCatRequest>).Handle(catRequest);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
令人不安的線路是這樣的:
(multiAnimalHandler as IRequestHandler<TCatResponse, TCatRequest>).Handle(catRequest);
代碼將呼叫HandleDogRequest而不是HandleCatRequest,這是我所期望的。
上面的代碼將產生以下輸出:
Woof!
Miav!
Woof!
Woof!
我做錯了什么或錯過了什么?
謝謝!
編輯:解決
在我的特定用例中,我可以將我的物件型別轉換為具體實作。沒有那么漂亮的代碼,但它有效。
IRequestHandler<TCatResponse, TCatRequest>(invokable).Handle(catRequest)
uj5u.com熱心網友回復:
你的通用介面有一個分配給它的 guid,所以通用介面的所有具體實作都將共享相同的 guid,這對于使用as運算子的型別轉換介面來說不是一件好事。查找僅適用于找到的 guid 的第一個實體。
每個不同的界面都需要一個唯一的 guid。這就是您的代碼無法正常作業的原因。這是一個長期存在的問題,可以追溯到十多年前:
通用介面和 GUID
還相關:
Delphi - 如何使用具有通用界面 GUID 的支持?
您將不得不介紹一些助手,例如:
type
IRequestHandler<TResponse: record; TRequest: record> = Interface(IInvokable)
function Handle(ARequest: TRequest): TResponse;
end;
TCatRequest = record
end;
TCatResponse = record
end;
ICatRequestHandler = interface(IRequestHandler<TCatResponse, TCatRequest>)
['{5D2B15AC-B11D-49B4-8249-65D42596CEA9}']
end;
TDogRequest = record
end;
TDogResponse = record
end;
IDogRequestHandler = interface(IRequestHandler<TDogResponse, TDogRequest>)
['{9637C82D-97D3-4F82-B8B2-89CE22092438}']
end;
TMultiAnimalHandler = class(TInterfacedObject, ICatRequestHandler, IDogRequestHandler)
public
function ICatRequestHandler.Handle = HandleCatRequest;
function HandleCatRequest(ARequest: TCatRequest): TCatResponse;
function IDogRequestHandler.Handle = HandleDogRequest;
function HandleDogRequest(ARequest: TDogRequest): TDogResponse;
end;
...
var
catHandler: ICatRequestHandler;
dogHandler: IDogRequestHandler;
multiAnimalHandler: TMultiAnimalHandler;
dogRequest: TDogRequest;
catRequest: TCatRequest;
begin
try
multiAnimalHandler := TMultiAnimalHandler.Create;
dogHandler := multiAnimalHandler;
catHandler := multiAnimalHandler;
dogHandler.Handle(dogRequest);
catHandler.Handle(catRequest);
(multiAnimalHandler as IDogRequestHandler).Handle(dogRequest);
(multiAnimalHandler as ICatRequestHandler).Handle(catRequest);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/402523.html
標籤:
