2012-02-17 11 views
7

hi all :) nó là câu hỏi đầu tiên của tôi tại stackoverflow :)Có thể tạo cá thể TRttiMethod cho TRttiType bằng TypeKind = tkMethod không?

trong Delphi XE2 RTTI chúng tôi có lớp TRttiMethod và nó có chức năng CreateImplementation() Mà cho phép để tự động tạo ra thủ tục hoặc hàm với cùng một chữ ký và một phương pháp anonimous như nó thân hình.

sử dụng TRttiContext.getMethods()/getMethod() chúng tôi có thể thu thập các phương pháp lớp - bộ sưu tập của TRttiMethod.

tài liệu nói (http://docwiki.embarcadero.com/VCL/en/RTTI.TRttiMethod) không tạo TRTTiMethod trực tiếp và sử dụng getMethods() để lấy các phiên bản của nó.

vì vậy, nếu chúng tôi có trường hợp TRTTIMethod, chúng tôi có thể tự động tạo phương thức có cùng chữ ký và gọi sau.

câu hỏi là .. ví dụ: chúng tôi có TNotifyEvent ... TRttiContext.getType(typeinfo(TNotifyEvent)) trả về TRttiType đối tượng thể hiện có typekind = tkMethod. chúng ta biết rằng chữ ký của TNotifyEvent là thủ tục (người gửi: TObject) của đối tượng;

là có thể nhận được TRttiMethod cho điều này? Tôi muốn tạo động eventHandler cho sự kiện bằng cách sử dụng TRttiMethod.CreateImplementation() hoặc có thể có cách khác để tự động tạo triển khai phương pháp?

PS: ý tưởng là tạo thứ gì đó như Chuỗi sự kiện. Tại thời gian biên dịch, chúng tôi không biết loại sự kiện/chữ ký, vì vậy chúng tôi có thể sử dụng Generics cho điều này như TEvenChain <TNotifyEvent>. Chuỗi có bộ sưu tập về các trình xử lý sự kiện đã đăng ký, vì chúng ta không biết kiểu xử lý tại thời gian biên dịch, chúng ta phải tạo nó một cách động và trình xử lý đó chỉ nhận các tham số của nó và gọi các trình xử lý đã đăng ký với chúng.

update: đây là một số mã (ý tưởng là để tạo ra các event handler chuỗi):

procedure TMainForm.FormCreate(Sender: TObject); 
begin 
    FEventChain := TNotifyChain.Create(); 
    FEventChain.AddHandler(event1); 
    FEventChain.AddHandler(event2); 

    TestButton.OnClick := FEventChain.EventHandler; 
end; 

Event1 & event2 là phương pháp (sender : TObject) hình thức; nó không phải là ví dụ generic (T trong trường hợp này là NotifyEvent/TChain <TNotifyEvent>) TEventChain.EventHandlerTNotifyEvent quá

TNotifyChain

TNotifyChain = class(TObject) 
    strict private 
    FEvent : TNotifyEvent; 
    FItems : TList<TNotifyEvent>; 

    FCtx : TRttiContext; 
    public 
    procedure TestNotifyHandler(sender : TObject); virtual; abstract; 

    constructor Create(); 
    procedure AddHandler(eh : TNotifyEvent); 
    property EventHandler : TNotifyEvent read FEvent; 
end; 

EventHandler sở hữu được ánh xạ tới FEvent biến. Và FEvent không được gán vì chúng tôi cho rằng loại sự kiện/xử lý không xác định.

như vậy trong constructor chúng ta tạo ra phương pháp ảo với TNotifyEvent chữ ký và gán mã của nó để FEvent:

constructor TNotifyChain.Create(); 
var st: TRttiType; 
    //et : TRttiMethodType; 
    Callback : TMethodImplementationCallback; 
    rttiMethod : TRttiMethod; 
    m : TMethod; 
    mi : TMethodImplementation; 
begin 
    inherited; 
    FItems := TList<TNotifyEvent>.Create(); 

    FCtx := TRttiContext.Create(); 

    //et := FCtx.GetType(typeinfo(TNotifyEvent)) as TRttiMethodType; 
    st := FCtx.GetType(self.ClassType); 


    rttiMethod := st.GetMethod('TestNotifyHandler'); 

    Callback := procedure(UserData: Pointer; 
         const Args: TArray<TValue>; 
         out Result: TValue) 
      var i : integer; 
       e : TMethod; 
      begin 

       for i := 0 to FItems.Count - 1 do begin 
        e := TMethod(Fitems[i]); 
        result := Invoke(e.Code, args, rttiMethod.CallingConvention, nil); 
       end; 
      end; 


    mi := rttiMethod.CreateImplementation(self, Callback); 

    m.data := self; 
    m.Code := mi.CodeAddress; 
    FEvent := TNotifyEvent(m); 
end; 

ở đây tôi sử dụng TestNotifyHandler phương pháp để tạo ra bộ xử lý thực tế với cùng một chữ ký sử dụng TRttimethod.CreateImplementation()

vì vậy tôi cho rằng , có một cách để tạo ra việc thực hiện xử lý sự kiện khi chạy bằng cách sử dụng TRttiMethodType từ TNotifyEvent vì nó có thông tin về kiểu/số đếm và quy ước gọi của sự kiện thực tế được sử dụng (trong trường hợp chung).

+0

Bạn đã nhận được bao nhiêu tiền, vui lòng chia sẻ. – menjaraz

+0

@menjaraz Tôi chưa giải quyết được vấn đề này. Đó không phải là nhiệm vụ "thực sự" đối với tôi, "chỉ vì vui". Tôi đã viết bài viết về điều này trong blog của tôi: http://teran.karelia.pro/articles/item_4508.html (nhưng ban đầu nó bằng tiếng Nga); bạn có thể sử dụng Google để dịch sang tiếng Anh [link] http://translate.google.com/translate?sl=ru&tl=vi&js=n&prev=_t&hl=ru&ie=UTF-8&layout=2&eotf=1&u=http%3A%2F% 2Fteran.karelia.pro% 2Farticles% 2Fitem_4508.html & act = url – teran

+0

Cảm ơn bạn đã trả lời. – menjaraz

Trả lời

4

A TRttiType với typekind TkMethod sẽ được biểu diễn dưới dạng TRttiMethodType. Bạn không thể nhận được một TRttiMethod từ nó, bởi vì nó không phải là một phương pháp; đó là một con trỏ phương pháp, nhưng nếu bạn nhìn vào TRttiMethodType và phương pháp Invoke của nó, bạn sẽ tìm thấy chính xác những gì bạn cần.

+0

cảm ơn bạn đã trả lời. Tôi không shure rằng 'TRttiMethodType.Invoke' là những gì tôi cần; bởi vì nó được sử dụng để gọi các phương thức thực sự hiện có của đối tượng. Trong trường hợp của tôi không có phương pháp như vậy và tôi phải tạo ra nó trước đây. Tôi đã thêm một số nguồn của lớp 'TNotifyChain' để chứng minh vấn đề. – teran