2010-09-24 19 views
5

Tüm olayları belirli bir öznitelikle alıyorum ve bu olayları başka bir yönteme ekleyerek değiştirmek istiyorum.Bir etkinlikte atanan yöntemi nasıl değiştirebilirim?

var type = GetType(); 
var events = type.GetEvents().Where(e => e.GetCustomAttributes(typeof(ExecuteAttribute), false).Length > 0); 

foreach (var e in events) 
{ 
    var fi = type.GetField(e.Name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); 
    var d = (Delegate)fi.GetValue(this); 
    var methods = d.GetInvocationList(); 
    foreach (var m in methods) 
    { 
     var args = e.EventHandlerType.GetMethod("Invoke").GetParameters().Select(p => Expression.Parameter(p.ParameterType, "p")).ToArray(); 
     var body = m.Method.GetMethodBody(); 

     /** 

     TODO: 

     Create a new method with the body of the previous 
     and add a call to another method 

     Remove current method 
     Add the new created method 

     **/ 
    } 
} 

Temel olarak ne yorumda bulunuyorum. Etkinliğin abone edilmiş yöntemlerini "değiştir". Sanırım buna abone olamam, çünkü yöntemin büyük işleyiciye (yeni yöntem) geçtiği parametreleri geçmem gerekiyor.

Bir örnek daha temel alan on this question.

var e += (x) => 
{ 
    var y = x; 

    BigHandler(x); // injected code 
}; 

Ya da bu:

var e += (x) => // new method 
{ 
    previousE(x); // previous method 

    BigHandler(x); // additional code 
} 

Bunu nasıl yapabilirim böyle bir şey için

var e += (x) => 
{ 
    var y = x; 
}; 

: Ben bu dönüştürmek istediğiniz?


büyük hedef:

Ben Bir olay ateşlendiğinde "algılamak" ve bir yöntemi çağırmanız gerekir

. Kullanmakta olduğu parametreleri de göndermem gerek.

public delegate void OnPostSaved(Post p); 
[Execute] 
public event OnPostSaved PostSaved; 

public void Save() 
{ 
    /* save stuff */ 
    // assume that there is already an event subscribed 
    PostSaved(post); 
} 

Sonra işleyicisi yöntemi ben XYZ gelen bir olay kovuldu eğer kovuldu hangi olay kontrol kontrol parametresini almak ve bir şeyler yapabilir:

Yani böyle bir şey yapabilirsiniz. Örneğin:

public void BigHandler(string eventName, params object[] p) 
{ 
    if (eventName == "PostSaved") 
    { 
     var post = p[0] as Post; 
     MessageBoard.Save("User posted on the blog: " + post.Content); 
    } 
} 

Ben PostSharp kullanılarak elde edilebilir biliyorum ama bunu kullanamazsınız. Başka bir çözüme ihtiyacım var.


İlgili Bir çözüm ne fazla bilgi üzerinde bulamadık 2010-09-27


Güncelleme Hala yardıma ihtiyacım var. +150 lütuf eklendi.

cevap

4

Sadece adresinden ekliyorsanız, bu gerçekten çok kolay - tüm abone delegeleri veya bunun gibi herhangi bir şeyi getirmeniz gerekmez; Sadece yansıma ile abone:

var type = GetType(); 
// Note the small change here to make the filter slightly simpler 
var events = type.GetEvents() 
       .Where(e => e.IsDefined(typeof(ExecuteAttribute), false)); 

foreach (var e in events) 
{ 
    // "handler" is the event handler you want to add 
    e.AddEventHandler(this, handler); 
} 

Şimdi, ne yapmak istediğinize dair bir varsayımda yaptık - yani olay ortaya kez her defasında yöntem diyoruz. Bu, yöntemini, bir olay işleyicisine, orijinal kodunuzun yapacağı şey olan bir kez numaralı çağrıyı çağırmakla aynı şey değildir. Bu çok daha sert ...ama gerçekten buna ihtiyacın var mı?

(buradaki esas amaç hakkında daha fazla bilgi verebilir, bu gerçekten yardımcı olacaktır.) Burada sağladık kod bakılmaksızın olay uygulanmaktadır nasılçalışması gerektiğini

Not - Götürmezse Saha benzeri bir olay olduğuna güvenme.

DÜZENLEME: Biz gerekli temsilci kesin tipini oluşturmak için ne

using System; 
using System.Reflection; 

class CustomEventArgs : EventArgs {} 

delegate void CustomEventHandler(object sender, CustomEventArgs e); 

class Publisher 
{ 
    public event EventHandler PlainEvent; 
    public event EventHandler<CustomEventArgs> GenericEvent; 
    public event CustomEventHandler CustomEvent; 

    public void RaiseEvents() 
    { 
     PlainEvent(this, new EventArgs()); 
     GenericEvent(this, new CustomEventArgs()); 
     CustomEvent(this, new CustomEventArgs()); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     Publisher p = new Publisher(); 

     Type type = typeof(Publisher); 

     foreach (EventInfo eventInfo in type.GetEvents()) 
     { 
      string name = eventInfo.Name; 
      EventHandler handler = (s, args) => ReportEvent(name, s, args); 
      // Make a delegate of exactly the right type 
      Delegate realHandler = Delegate.CreateDelegate(
       eventInfo.EventHandlerType, handler.Target, handler.Method); 
      eventInfo.AddEventHandler(p, realHandler); 
     } 

     p.RaiseEvents(); 
    } 

    static void ReportEvent(string name, object sender, EventArgs args) 
    { 
     Console.WriteLine("Event {0} name raised with args type {1}", 
          name, args.GetType()); 
    } 
} 

Not: Tamam, normal eventing kalıpla eşleşen herhangi bir olaya düz EventHandler temsilci eklemek nasıl gösteren eksiksiz örnek - Fakat her şeyin normal olay desenini takip ettiği sürece bunu uyumlu yönteminden yapabileceğimizi biliyoruz.

+0

"Daha büyük hedefi" ekledim. Şu anki cevabınız yakın, özür dilerim ki, abone olmakta olan metodları almam gerektiğini söylemeyi unutmuşum. Daha fazla bilgi ekledim ... – BrunoLM

+0

@BrunoLM: Bu sadece uygun delege oluşturma meselesi. Şimdi dışarı çıkıyorum, ama o zamana kadar çözmediyseniz yaklaşık bir saat sonra bakacağım. Lambda ifadeleri senin arkadaşın olabilir. –

+0

@Jon Skeet: Hala anlamadım ... Olayın kullandığı nesneyi nasıl alabilirim? Düşünebilmemin tek yolu, aynı yöntemi değiştirmek. BigHandler (eventName, params_from_the_event.ToArray () ' – BrunoLM

İlgili konular