2011-11-29 28 views
10

Tôi đang sử dụng thư viện bên thứ ba delphi rất lớn mà không có mã nguồn, thư viện này có một số lớp với phương thức trừu tượng. Tôi cần phải xác định khi một phương pháp abtract được thực hiện bởi một lớp Descendant trong thời gian chạy để tránh EAbstractError: Abstract Error và hiển thị thông báo tùy chỉnh cho người dùng hoặc sử dụng một lớp khác thay thế.Làm thế nào tôi có thể xác định xem một phương pháp trừu tượng có được triển khai không?

ví dụ trong mã này Tôi muốn kiểm tra trong thời gian chạy nếu MyAbstractMethod được triển khai.

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; 

Làm cách nào để xác định xem phương pháp trừu tượng có được triển khai trong lớp Con cháu trong thời gian chạy không?

Trả lời

10

bạn có thể sử dụng Rtti, hàm GetDeclaredMethods nhận danh sách tất cả các phương thức được khai báo theo loại được phản ánh (hiện tại). Vì vậy, bạn có thể kiểm tra xem phương thức có trong danh sách được trả về bởi hàm này hay không.

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; 

hoặc bạn có thể so sánh Parent.Name tài sản của TRttiMethod và kiểm tra xem trận đấu với tên lớp hiện hành.

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

Xem xét việc triển khai phương thức TStream.Seek() trong mã nguồn VCL. Nó thực hiện một loại tương tự như kiểm tra hậu duệ-overriden như bạn đang tìm kiếm, và không liên quan đến tra cứu TRttiContext để làm điều đó, chỉ là một vòng lặp đơn giản thông qua các mục nhập vtable Parent/Child của nó.

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

Cảm ơn, nhưng nếu sử dụng cách này, tôi cần triển khai chức năng cho từng loại lớp và tôi sẽ tìm một giải pháp tổng quát hơn. – Salvador

+0

Tôi không chắc liệu mã của bạn có chính xác không. 'ImplementsAbstractMethod (TChild2.Create)' sẽ trả về true, nhưng không phải 'TChild2', cũng không phải' TDescendantBase' đã ghi đè abstract 'MyAbstractMethod' của' TMyBaseClass'. http://pastebin.com/JufNPJkg –

+0

@rinntech: Cảm ơn những người đứng đầu. Tôi đã cập nhật câu trả lời với mã đúng. –

Các vấn đề liên quan