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

Я использую очень большую стороннюю библиотеку 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 во время выполнения?

Ответ 1

вы можете использовать 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 и проверить соответствие имя текущего класса.

function MethodIsImplemented(const AClass:TClass;MethodName : string): Boolean;
var
  m   : TRttiMethod;
begin
  Result := False;
  m:=TRttiContext.Create.GetType(AClass.ClassInfo).GetMethod(MethodName);
  if m<>nil then
   Result:=CompareText(AClass.ClassName,m.Parent.Name)=0; 
end;

Ответ 2

Посмотрите на реализацию метода TStream.Seek() в исходном коде VCL. Он выполняет подобный тип проверки по возврату потомков, как вы ищите, и не требует поиска TRttiContext для этого, просто простую петлю через записи родительского/дочернего vtable.

Ответ 3

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;