Как я могу определить, реализован ли абстрактный метод? - PullRequest
10 голосов
/ 29 ноября 2011

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

например, в этом коде я хочу проверить во время выполнения, реализован ли MyAbstractMethod.

type
  TMyBaseClass = class
  public
    procedure MyAbstractMethod; virtual; abstract;
  end;

  TDescendantBase = class(TMyBaseClass)
  public
  end;

  TChild = class(TDescendantBase)
  public
    procedure MyAbstractMethod; override;
  end;

  TChild2 = class(TDescendantBase)
  end;

Как я могу определить, реализован ли абстрактный метод в классе Descendant во время выполнения?

Ответы [ 3 ]

10 голосов
/ 29 ноября 2011

вы можете использовать Rtti, функция GetDeclaredMethods получить список всех методов, которые объявлены в отраженном (текущем) типе.Таким образом, вы можете проверить, присутствует ли метод в списке, возвращаемом этой функцией.

function MethodIsImplemented(const AClass:TClass;MethodName : string): Boolean;
var
  m   : TRttiMethod;
begin
  Result := False;
  for m in TRttiContext.Create.GetType(AClass.ClassInfo).GetDeclaredMethods do
  begin
   Result := CompareText(m.Name, MethodName)=0;
   if Result then
    break;
  end;
end;

или вы можете сравнить Parent.Name свойство TRttiMethod и проверить, совпадают ли с именем текущего класса.

5 голосов
/ 29 ноября 2011
function ImplementsAbstractMethod(AObj: TMyBaseClass): Boolean;
type
  TAbstractMethod = procedure of object;
var
  BaseClass: TClass;
  BaseImpl, Impl: TAbstractMethod;
begin
  BaseClass := TMyBaseClass;
  BaseImpl := TMyBaseClass(@BaseClass).MyAbstractMethod;
  Impl := AObj.MyAbstractMethod;
  Result := TMethod(Impl).Code <> TMethod(BaseImpl).Code;
end;
4 голосов
/ 29 ноября 2011

Посмотрите на реализацию 32-битной версии метода TStream.Seek() в исходном коде VCL (в Classes.pas).Он выполняет проверку, чтобы убедиться, что 64-битная версия Seek() была переопределена перед вызовом.Для этого не требуется TRttiContext поисков, просто цикл по записям в родительской / дочерней VTable, аналогично тому, как показывает ответ Зоэ.

...