Кто-нибудь еще заметил такое поведение в Delphi с использованием QueryInterface? - PullRequest
0 голосов
/ 11 августа 2010

Вот мои типы ...

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 ]

7 голосов
/ 11 августа 2010

Я предполагаю, что вы нарушаете правила:

QueryInterface поместит интерфейс в f, который вы запросили.Вы несете ответственность за то, что f имеет соответствующий тип.Поскольку второй параметр не введен, компилятор не может предупредить вас о вашей ошибке.

3 голосов
/ 11 августа 2010

Я бы сказал, что лучший синтаксис - ни QueryInterface, ни f := fb.Это тот, который вы прокомментировали:

f := fb as IBah; //causes compile error

, и это именно потому, что он имеет проверку типов, которая покрывает проблему с QueryInterface, что он не проверяет свои аргументы.

2 голосов
/ 11 августа 2010

Обратите внимание, что f: = Fb как IFoo, поддержка вызовов (Fb, IFoo) и т. Д. Все они вызывают QueryInterface в фоновом режиме. Таким образом, метод QueryInterface используется, но вы получаете хороший синтаксис с автокастингом, как и методы типа support.

...