2008-12-30 20 views
44

मैं क्रम में एक ईवेंट हैंडलर बताए कर रहा हूँ और यह एक जगह है कि कई बार कहा जा सकता है में है, तो एक ही घटना के लिए एक ही हैंडलर के कई कार्य को रोकने के लिए सिफारिश की अभ्यास क्या है।की रोकथाम में एक ही ईवेंट हैंडलर काम कई बार

object.Event += MyFunction 

एक जगह है कि एक से अधिक बार हैंडलर 'एन' (बेशक) बार निष्पादित करेंगे बुलाया जाएगा में इस जोड़ना।

मैं जोड़ने के लिए

object.Event -= MyFunction; 

object.Event += MyFunction; 

के माध्यम से यह काम करता है लेकिन किसी भी तरह बंद लगता है प्रयास करने से पहले किसी भी पिछले हैंडलर को हटाने का सहारा लिया। उचित परिदृश्य पर कोई सुझाव;) इस परिदृश्य के।

+1

पहले ईवेंट को हटाने का आपका समाधान और फिर जोड़ना वास्तव में http://stackoverflow.com/questions/937181/c-sharp-pattern-to-prevent-an-event-handler-hooked- दो बार (इस प्रश्न में इस विषय के अधिक जवाब भी हैं) – OneWorld

+0

संभावित डुप्लिकेट [यह सुनिश्चित करने के लिए कि एक ईवेंट केवल एक बार सदस्यता लेता है] (http://stackoverflow.com/questions/367523/how-to-ensure-an-event -इस-केवल-सब्सक्राइब-टू-एक बार) –

उत्तर

36

Baget एक स्पष्ट कार्यान्वित घटना का उपयोग कर (वहाँ एक मिश्रण है, हालांकि स्पष्ट इंटरफेस कार्यान्वयन और पूर्ण घटना वाक्य रचना की वहाँ) के बारे में सही है। आप शायद इस के साथ भाग प्राप्त कर सकते हैं:

private EventHandler foo; 

public event EventHandler Foo 
{ 
    add 
    { 
     // First try to remove the handler, then re-add it 
     foo -= value; 
     foo += value; 
    } 
    remove 
    { 
     foo -= value; 
    } 
} 

कि कुछ अजीब किनारे मामलों हो सकता है अगर आप कभी भी जोड़ सकते हैं या बहुस्त्र्पीय प्रतिनिधियों को दूर है, लेकिन यह संभावना नहीं है। इसे सावधानीपूर्वक दस्तावेज़ीकरण की भी आवश्यकता होती है क्योंकि यह सामान्य रूप से कार्य नहीं करता है।

+0

कंपाइलर त्रुटि से बचने के लिए, ईवेंट को फायर करते समय ईवेंट का 'निजी' नाम उपयोग करें। 'फू' बनाम 'फू' – Zyo

4

मैं एक रास्ता है कि एक निर्माता में उदाहरण के लिए एक बार निष्पादित कर रहा है, में एक घटना हैंडलर जोड़ने के लिए जाते हैं।

2

आप delgates का अपना स्वयं का भंडारण को लागू है, और जब उन्हें घटना को जोड़ने विशिष्टता के लिए देख सकते हैं। उदाहरण के लिए नीचे EventOwner2 कक्षा देखें। मुझे नहीं पता कि यह प्रदर्शन के अनुसार कैसे कर रहा है, लेकिन फिर से, यह हमेशा एक मुद्दा नहीं है।

using System; 
using System.Collections.Generic; 

namespace EventExperiment 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      IEventOwner e=new EventOwner2(); 
      Subscriber s=new Subscriber(e); 
      e.RaiseSome(); 
      Console.ReadKey(); 
     } 
    } 

    /// <summary> 
    /// A consumer class, subscribing twice to the event in it's constructor. 
    /// </summary> 
    public class Subscriber 
    { 
     public Subscriber(IEventOwner eventOwner) 
     { 
      eventOwner.SomeEvent += eventOwner_SomeEvent; 
      eventOwner.SomeEvent += eventOwner_SomeEvent; 
     } 

     void eventOwner_SomeEvent(object sender, EventArgs e) 
     { 
      Console.WriteLine(DateTimeOffset.Now); 
     } 

    } 

    /// <summary> 
    /// This interface is not essensial to this point. it is just added for conveniance. 
    /// </summary> 
    public interface IEventOwner 
    { 
     event EventHandler<EventArgs> SomeEvent; 
     void RaiseSome(); 
    } 

    /// <summary> 
    /// A traditional event. This is raised for each subscription. 
    /// </summary> 
    public class EventOwner1 : IEventOwner 
    { 
     public event EventHandler<EventArgs> SomeEvent = delegate { }; 
     public void RaiseSome() 
     { 
      SomeEvent(this,new EventArgs()); 
     } 
    } 
    /// <summary> 
    /// A custom event. This is raised only once for each subscriber. 
    /// </summary> 
    public class EventOwner2 : IEventOwner 
    { 
     private readonly List<EventHandler<EventArgs>> handlers=new List<EventHandler<EventArgs>>(); 
     public event EventHandler<EventArgs> SomeEvent 
     { 
      add 
      { 
       lock (handlers) 
        if (handlers!=null&&!handlers.Contains(value)) 
        { 
         handlers.Add(value); 
        } 
      } 
      remove 
      { 
       handlers.Remove(value); 
      } 
     } 
     public void RaiseSome() 
     { 
      EventArgs args=new EventArgs(); 
      lock(handlers) 
      foreach (EventHandler<EventArgs> handler in handlers) 
      { 
       handler(this,args); 
      } 
     } 
    } 
} 
0

'ऑब्जेक्ट' का एक्सेस संशोधक क्या है?

यदि यह निजी है, आप केवल युक्त वस्तु ईवेंट हैंडलर स्थापित करने के बारे में चिंता करने की जरूरत है। यदि यह आंतरिक है, तो आपको ईवेंट हैंडलर सेटिंग वाली असेंबली सेटिंग के बारे में चिंता करने की आवश्यकता है। यदि यह सार्वजनिक है, तो यह व्यापक रूप से खुला है।

'वस्तु' वाले वर्ग पर निजी बनाया जा सकता है, तो आप अपने चेक और अधिक स्थानीय कक्षा में ईवेंट हैंडलर काम को नियंत्रित करके कुशल बना सकते हैं।

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