2011-03-15 11 views
5

का उपयोग करके किसी ऐसी कक्षा पर विचार करें जिसमें कुछ ईवेंट हैं। यह घटना सूची बढ़ने जा रही है। कुछ वैकल्पिक हैं। दूसरों की आवश्यकता है।जांचें कि रनटाइम के दौरान किसी दिए गए ईवेंट की सदस्यता ली गई है, प्रतिबिंब

कुछ आरंभिक सत्यापन को सरल बनाने के लिए मेरे पास एक कस्टम विशेषता है जो किसी ईवेंट को आवश्यकतानुसार चिह्नित करती है। उदाहरण के लिए:

[RequiredEventSubscription("This event is required!")] 
    public event EventHandler ServiceStarted; 

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

प्रतिबिंबित किए बिना ServiceStarted.GetInvocationList नौकरी करता है। लेकिन घटना इस सूची से आनी चाहिए: var eventList = this.GetType()। GetEvents()। ToList();

क्या कोई ईवेंट देखने के लिए कोई तरीका है, किसी इवेंट सूची से, प्रतिबिंब का उपयोग करके सब्सक्राइब किया गया है?

private void CheckIfRequiredEventsAreSubscribed() 
    { 
     var eventList = GetType().GetEvents().ToList().Where(e => Attribute.IsDefined(e, typeof(RequiredEventSubscription))); 

     StringBuilder exceptionMessage = new StringBuilder(); 
     StringBuilder warnMessage = new StringBuilder(); 

     foreach (var evt in eventList) 
     { 
      RequiredEventSubscription reqAttr = (RequiredEventSubscription) evt.GetCustomAttributes(typeof(RequiredEventSubscription), true).First(); 
      var evtDelegate = this.GetType().GetField(evt.Name, BindingFlags.Instance | BindingFlags.NonPublic); 
      if (evtDelegate.GetValue(this) == null) 
      { 
       warnMessage.AppendLine(reqAttr.warnMess); 
       if (reqAttr.throwException) exceptionMessage.AppendLine(reqAttr.warnMess); 
      } 
     } 
     if (warnMessage.Length > 0) 
      Console.WriteLine(warnMessage); 
     if (exceptionMessage.Length > 0) 
      throw new RequiredEventSubscriptionException(exceptionMessage.ToString()); 
    } 

बहुत धन्यवाद !!:

- - [अपडेट] यहाँ एक संभव समाधान अमी के जवाब पर आधारित है

+3

IMHO, अगर एक घटना की सदस्यता के लिए आवश्यक है , इसे पहले स्थान पर न करें बल्कि अपनी कक्षा के निर्माता के लिए एक प्रतिनिधि पैरामीटर न बनाएं। –

+0

प्रमाणीकरण क्या कर रहा है, और इस संदर्भ में "आवश्यक" का क्या अर्थ है? किसके लिए/क्या आवश्यक है? –

+0

@ डैनियल, यह मेरा पहला दृष्टिकोण था, लेकिन पूरे कोड में इतने सारे प्रतिनिधि भेजकर मुझे इस प्रयोग में ले जाया गया। – Bruno

उत्तर

4

यहां कुछ प्रमुख डिजाइन मुद्दे हैं। आम तौर पर, किसी ऑब्जेक्ट से पूछने का कोई तरीका नहीं है कि उसके ईवेंट के ग्राहक कौन हैं। यह बेहद असामान्य है कि किसी को इस कार्यक्षमता चाहते थे, लेकिन अगर आप वास्तव में यह चाहते हैं, तो आप कक्षाएं किसी भी तरह इस पर्दाफाश करने के लिए, उदाहरण के लिए, इस तरह के रूप में एक विधि के साथ एक अंतरफलक को लागू करने से मिलना चाहिए: वैसे भी

public IEnumerable<Delegate> GetSubscribers(string eventName); 

, पूछे गए प्रश्न का उत्तर देने के लिए, आप प्रतिबिंब का उपयोग कर सकते हैं, लेकिन केवल तभी जब आप जानते हैं कि ग्राहकों को कैसे बनाए रखा जा रहा है। उदाहरण के लिए, यह सोचते हैं कि सभी घटनाओं सी # क्षेत्र-तरह की घटनाओं की वर्तमान कार्यान्वयन के साथ लागू किया जाता है, तो आप (दृढ़ता से हतोत्साहित) की तरह कुछ कर सकते हैं:

object o = ... 

var unsubscribedEvents = 
    from e in o.GetType().GetEvents() 
    where Attribute.IsDefined(e, typeof(RequiredEventSubscriptionAttribute)) 
    let field = o.GetType() 
       .GetField(e.Name, BindingFlags.NonPublic | BindingFlags.Instance) 
       .GetValue(o) 
    where field == null 
    select field; 

var isValid = !unsubscribedEvents.Any(); 
+0

मैं डिज़ाइन दोष के बारे में आपका बिंदु देखता हूं:/फिर भी आपका समाधान मुझे एक अच्छी दिशा में ले जाता है! GetField (-वेन्टनाम-) और बाध्यकारी झंडे समस्या हल! – Bruno

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