Как вы переопределяете реализацию делегированного метода? - PullRequest
4 голосов
/ 02 марта 2012

В Delphi 2007 я использую один класс для реализации одного из поддерживаемых интерфейсов второго класса. Это работает. Помощь Delphi гласит:

По умолчанию, используя ключевое слово Implements делегирует весь интерфейс методы. Тем не менее, вы можете использовать методы разрешения предложений или объявить методы в вашем классе, которые реализуют некоторые методы интерфейса для переопределить это поведение по умолчанию.

Однако, когда я объявляю метод во втором классе, у которого есть совпадающая сигнатура одного из методов интерфейса, он не вызывается.

Интересно, это потому, что я получаю доступ к классу через другой интерфейс, когда создаю его.

Ниже приведена тестовая программа, демонстрирующая мою проблему:

program Project1;

{$APPTYPE CONSOLE}

type
  IInterface1 = interface
  ['{15400E71-A39B-4503-BE58-B6D19409CF90}']
    procedure AProc;
  end;

  IInterface2 = interface
  ['{1E41CDBF-3C80-4E3E-8F27-CB18718E8FA3}']
  end;

  TDelegate = class(TObject)
  protected
    procedure AProc;
  end;

  TMyClass = class(TInterfacedObject, IInterface1, IInterface2)
  strict private
    FDelegate: TDelegate;
    property Delegate: TDelegate read FDelegate implements IInterface1;
  public
    constructor Create;
    destructor Destroy; override;
    procedure AProc;
  end;

procedure TDelegate.AProc;

begin
  writeln('TClassDelegate.AProc');
end;

constructor TMyClass.Create;
begin
  inherited;
  FDelegate := TDelegate.Create;
end;

destructor TMyClass.Destroy;
begin
  FDelegate.Free;
  inherited;
end;

procedure TMyClass.AProc;

begin
  writeln('TMyClass.AProc');
end;

var
  MyObj : IInterface2;

begin
    MyObj := TMyClass.Create;
   (MyObj as IInterface1).AProc;
end.

Когда я запускаю это, я получаю в качестве вывода:

TClassDelegate.AProc

Что я хочу, это:

TMyClass.AProc

Любая помощь приветствуется.

Ответы [ 4 ]

5 голосов
/ 02 марта 2012

кажется, что вы должны переопределить свой метод следующим образом:

TMyClass = class(TInterfacedObject, IInterface1, IInterface2)
strict private
  ....
  procedure test();
public
  ....
  procedure  IInterface1.AProc = test;
end;

procedure TMyClass.test;
begin
  writeln('TMyClass.AProc');
end;

, поэтому IInterface1.AProc для TMyClass отображается на Test() (не на FDelegate.AProc), а результат равен TMyClass.AProc

1 голос
/ 02 марта 2012

В документации прямо указано, что поведение, которое вы видите, соответствует указанному:

Если свойство делегата относится к типу класса, этот класс и его предки ищутся для методов, реализующих указанный интерфейс, прежде чем будет найден включающий класс и его предки.

Я предполагаю, что в полном примере у вас есть интерфейс с несколькими методами, и вы хотите получить большинство, указанное делегатом, и определенные, переопределенные реализующим классом. Я не понимаю, как этого достичь, используя только один класс, но это можно сделать, если вы введете второй класс:

program Project1;

{$APPTYPE CONSOLE}

type
  IInterface1 = interface
  ['{15400E71-A39B-4503-BE58-B6D19409CF90}']
    procedure AProc;
    procedure AnotherProc;
  end;

  TDelegate = class
  protected
    procedure AProc;
    procedure AnotherProc;
  end;

  TMyClass = class(TInterfacedObject, IInterface1)
  strict private
    FDelegate: TDelegate;
    property Delegate: TDelegate read FDelegate implements IInterface1;
  public
    constructor Create;
    destructor Destroy; override;
    procedure AProc;
  end;

  TMyOtherClass = class(TMyClass, IInterface1)
    procedure IInterface1.AProc = AProc;
  end;

procedure TDelegate.AProc;
begin
  writeln('TDelegate.AProc');
end;

procedure TDelegate.AnotherProc;
begin
  writeln('TDelegate.AnotherProc');
end;

constructor TMyClass.Create;
begin
  inherited;
  FDelegate := TDelegate.Create;
end;

destructor TMyClass.Destroy;
begin
  FDelegate.Free;
  inherited;
end;

procedure TMyClass.AProc;
begin
  writeln('TMyClass.AProc');
end;

var
  MyObj: IInterface1;

begin
  MyObj := TMyOtherClass.Create;
  MyObj.AProc;
  MyObj.AnotherProc;
  Readln;
end.

Как указывает @teran, если вы готовы переименовать свой метод, то есть более простое решение.

1 голос
/ 02 марта 2012

Часть упомянутой вами документации устарела.Если вы попытаетесь использовать разрешение метода для интерфейса, который используется в предложении implements, вы получите ошибку компилятора E2264: невозможно получить разрешение метода для интерфейса "% s" .

.Решение, показанное в приведенной выше ссылке - просто присвоить процедуре то же имя, которое объявлено в интерфейсе, - похоже, не работает и в Delphi XE (оно компилируется, но процедура не вызывается).

1 голос
/ 02 марта 2012

Это может быть связано с видимостью имущества.Каждый раз, когда я использую implements, свойства равны protected или public, то же самое для всех примеров, которые я мог найти в VCL (например, TAutoObjectEvent.

Попытка № 2:

Что произойдет, если вы удалите метод AProc() из TMyClass? Использует ли он затем метод TDelegate?

...