2011-11-29 32 views
10

私は非常に大きなデルファイサードパーティのライブラリをソースコードなしで使用していますが、このライブラリには抽象メソッドを持ついくつかのクラスがあります。私は、EAbstractError: Abstract Errorを避けるためにabtractメソッドが実行時にDescendクラスによっていつ実装されるかを決定し、ユーザにカスタムメッセージを表示するか、代わりに別のクラスを使用する必要があります。抽象メソッドが実装されているかどうかはどのように判断できますか?

たとえば、このコードでは、実行時に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クラスに実装されているかどうかを判断する方法はありますか。

答えて

10

あなたは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; 

か、TRttiMethodParent.Nameプロパティを比較し、現在のクラス名と一致するかどうかを確認することができます。

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; 
4

VCLソースコードのTStream.Seek()メソッドの実装を見てください。あなたが探しているような同様の子孫オーバーライドチェックを実行し、それを行うにはTRttiContextルックアップを伴わず、親/子vtableエントリを通る単純なループを実行します。

4
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; 
+0

このように使用すると、各クラスの種類ごとに関数を実装する必要があり、私はより一般的な解決策を先験します。 – Salvador

+0

あなたのコードが正しいかどうかわかりません。 'ImplementsAbstractMethod(TChild2.Create)'はtrueを返しますが、 'TChild2'も' TDescendantBase'も 'TMyBaseClass'の抽象的な' MyAbstractMethod'をオーバーライドしません。 http://pastebin.com/JufNPJkg –

+0

@rinntech:ヘッドアップありがとう。正しいコードで答えを更新しました。 –

関連する問題