2010-09-24 31 views
5

मुझे एक निश्चित विशेषता के साथ सभी घटनाएं मिल रही हैं, और मैं इन घटनाओं को किसी अन्य विधि में कॉल जोड़ने के लिए संशोधित करना चाहता हूं।मैं किसी ईवेंट पर निर्दिष्ट विधि कैसे बदल सकता हूं?

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 

     **/ 
    } 
} 

जो मैं चाहता हूं वह मूल रूप से ऊपर टिप्पणी की गई है। घटना के सब्सक्राइब किए गए तरीकों को "संशोधित करें"। मुझे लगता है कि मैं इसकी सदस्यता नहीं ले सकता, क्योंकि मुझे बड़े हैंडलर (नई विधि) में जाने वाली पैरामीटर को पारित करने की आवश्यकता है।

एक और उदाहरण on this question आधारित है।

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

    BigHandler(x); // injected code 
}; 

या इस:

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

    BigHandler(x); // additional code 
} 

मैं इसे कैसे कर सकते हैं कुछ इस तरह करने के लिए

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

: मैं इस परिवर्तित करना चाहते हैं?


बड़ा लक्ष्य:

मैं जब एक घटना निकाल दिया जाता है "का पता लगाने" और एक विधि कॉल करने की जरूरत है। मुझे इसका उपयोग करने वाले पैरामीटर भेजने की भी आवश्यकता है।

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); 
} 

तब मेरे हैंडलर विधि पर मैं जाँच कर सकते हैं XYZ से एक घटना निकाल दिया गया था जांच करें कि कौन घटना निकाल दिया गया था, पैरामीटर निकालते हैं और कुछ करना:

इसलिए मैं कुछ ऐसा कर सकते हैं। उदाहरण के लिए:

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); 
    } 
} 

मैं जानता हूँ कि यह PostSharp का उपयोग कर प्राप्त किया जा सकता है, लेकिन मैं इसका इस्तेमाल नहीं कर सकते हैं। मुझे एक और समाधान चाहिए।


संबंधित


अद्यतन 2010-09-27 मैं एक समाधान न अधिक जानकारी पर नहीं मिल सका यह, मुझे अभी भी मदद की ज़रूरत है। +150 बाउंटी जोड़ा गया।

उत्तर

4

यदि आप जोड़ रहे हैं, तो यह वास्तव में आसान है - आपको सभी सब्स्क्राइब किए गए प्रतिनिधियों या उसके जैसा कुछ भी लाने की आवश्यकता नहीं है; सिर्फ प्रतिबिंब के साथ सदस्यता लें:

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); 
} 

अब, मैं आप क्या करना चाहते हैं के बारे में एक धारणा बना दिया है - अर्थात् अपने विधि हर बार एक बार घटना उठाया है कहते हैं। यह आपकी विधि को कॉल करने जैसा नहीं है, हर बार एक ईवेंट हैंडलर को कहा जाता है जो आपका मूल कोड होता है। यह बहुत कठिन है ...लेकिन क्या आपको वाकई इसकी ज़रूरत है?

(आप यहाँ बड़ा लक्ष्य के बारे में अधिक जानकारी दे सकता है, तो यह वास्तव में मदद मिलेगी।)

ध्यान दें कि कोड मैं यहाँ प्रदान की है परवाह किए बिना काम करना चाहिए कि कैसे घटना कार्यान्वित किया जाता है की - ऐसा नहीं इस पर एक क्षेत्र की तरह घटना पर भरोसा नहीं है।

संपादित करें:

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()); 
    } 
} 

नोट कैसे हम प्रतिनिधि का सही प्रकार की आवश्यकता का निर्माण करने के लिए है: ठीक है, यहाँ एक पूरा कैसे आप जो सामान्य इवेंट नमूने का मिलान किसी भी घटना के लिए एक सादे EventHandler प्रतिनिधि जोड़ सकते हैं दिखा उदाहरण है - लेकिन हम जानते हैं कि हम संगत विधि से ऐसा कर सकते हैं, जब तक कि सबकुछ सामान्य घटना पैटर्न का पालन करता है।

+0

मैंने "बड़ा लक्ष्य" जोड़ा है। आपका वर्तमान उत्तर करीब है, खेद है कि मैं यह उल्लेख करना भूल गया था कि मुझे विधि सदस्यता लेने वाले पैरामीटर प्राप्त करने की आवश्यकता है। मैंने और जानकारी जोड़ दी है ... – BrunoLM

+0

@ ब्रूनोएलएम: यह सिर्फ उचित प्रतिनिधि के निर्माण के मामले में है, इसे देखकर। मैं अभी बाहर जा रहा हूं, लेकिन अगर आप इसे तब तक हल नहीं करते हैं, तो मुझे लगभग एक घंटे का समय लगेगा। Lambda अभिव्यक्ति अच्छी तरह से आपका दोस्त हो सकता है। –

+0

@ जोन स्कीट: मुझे अभी भी यह नहीं मिला है ... मैं उस वस्तु को कैसे प्राप्त कर सकता हूं जिस पर ईवेंट उपयोग कर रहा है? एकमात्र तरीका मैं सोच सकता हूं कि एक ही विधि को संशोधित करना है। मुझे कुछ बिगहैंडलर (eventName, params_from_the_event.ToArray () ' – BrunoLM

संबंधित मुद्दे

 संबंधित मुद्दे