Кто-нибудь еще заметил такое поведение в Delphi с использованием QueryInterface?
Вот мои типы...
unit unitTestInterfaces;
interface
type
IFoo = interface
['{169AF568-4568-429A-A8F6-C69F4BBCC6F0}']
function TestFoo1:string;
function TestFoo:string;
end;
IBah = interface
['{C03E4E20-2D13-45E5-BBC6-9FDE12116F95}']
function TestBah:string;
function TestBah1:string;
end;
TFooBah = class(TInterfacedObject, IFoo, IBah)
//IFoo
function TestFoo1:string;
function TestFoo:string;
//IBah
function TestBah1:string;
function TestBah:string;
end;
implementation
{ TFooBah }
function TFooBah.TestBah: string;
begin
Result := 'TestBah';
end;
function TFooBah.TestBah1: string;
begin
Result := 'TestBah1';
end;
function TFooBah.TestFoo: string;
begin
Result := 'TestFoo';
end;
function TFooBah.TestFoo1: string;
begin
Result := 'TestFoo1';
end;
end.
И вот мой код для запуска примера...
var
fb:TFooBah;
f:IFoo;
b:IBah;
begin
try
fb := TFooBah.Create;
/// Notice we've used IBah here instead of IFoo, our writeln() still outputs the
/// result from the TestBah() function, presumably because it's the "first" method
/// in the IBah interface, just as TestFoo1() is the "first" method in the IFoo
/// interface.
(fb as IUnknown).QueryInterface(IBah,f); //So why bother with this way at all??
//f := fb as IBah; //causes compile error
//f := fb; //works as expected
if Assigned(f)then
begin
writeln(f.TestFoo1); //wouldn't expect this to work since "f" holds reference to IBah, which doesn't have TestFoo1()
end;
(fb as IUnknown).QueryInterface(IBah,b);
if Assigned(f) then
begin
writeln(b.TestBah1);
end;
except on E:Exception do
writeln(E.Message);
end;
end.
Кажется, что при первом вызове QueryInterface, даже если мы назначаем неверный тип интерфейса для переменной "f", он все равно будет пытаться выполнить "первый" метод того, на что он указывает, в отличие от метода с имя "TestFoo1". Использование f:= fb работает, как и ожидалось, поэтому есть ли причина, по которой мы будем использовать QueryInterface вместо синтаксиса f:= fb?
3 ответа
Я предполагаю, что вы нарушаете правила здесь:
QueryInterface поместит интерфейс в f, который вы запросили. Вы несете ответственность за то, что f имеет соответствующий тип. Поскольку второй параметр не введен, компилятор не может предупредить вас о вашей ошибке.
Я бы сказал, что лучший синтаксис QueryInterface
ни то ни f := fb
один. Это тот, который вы прокомментировали:
f := fb as IBah; //causes compile error
и это именно потому, что он имеет проверку типов, которая покрывает проблему с QueryInterface
что он не проверяет свои аргументы.
Обратите внимание, что f:= Fb как IFoo, поддержка вызовов ( Fb, IFoo) и т. Д. Все они вызывают QueryInterface в фоновом режиме. Таким образом, метод QueryInterface используется, но вы получаете хороший синтаксис с автокастингом, как и методы, такие как поддержка.