2009-03-08 10 views
20

मैं एक ईवेंट को एक सहायक समारोह में पास करने के लिए देख रहा हूं। यह फ़ंक्शन ईवेंट के लिए एक विधि संलग्न करेगा। हालांकि, मुझे घटना को ठीक से गुजरने में परेशानी हो रही है। मैंने EventHandler<TEventArgs> पास करने का प्रयास किया है। यह संकलित करता है, लेकिन घटनाएं संलग्न नहीं होती हैं (लेकिन अभी भी जोड़े गए हैं; ऐसा लगता है कि इवेंट हैंडलर की एक प्रति बनाई गई है)।मैं सी # में किसी फ़ंक्शन में कोई ईवेंट कैसे पास कर सकता हूं?

उदाहरण के लिए, अगर मैं इस:

public event EventHandler<EventArgs> MyEvent; 

और सहायक समारोह:

public static void MyHelperFunction<TEventArgs>(EventHandler<TEventArgs> eventToAttachTo) 
{ 
    eventToAttachTo += (sender, e) => { Console.WriteLine("Hello world"); }; 
} 

और फोन करने वाले:

MyHelperFunction(MyEvent); 
MyEvent(null, new EventArgs()); // Does nothing. 
+0

@Strager: क्या आप इसका उपयोग करने के तरीके के बारे में बताते हुए थोड़ा सा विस्तार करेंगे? मैंने यह सवाल बहुत रोचक पाया लेकिन मुझे उपयोग के मामले को देखने में कठिनाई हो रही है। –

+0

@ जॉन फेमिनेला, मैं कुछ सहायक कार्यों का निर्माण कर रहा था, और एक सिंक्रनाइज़ रूप से एक घटना की प्रतीक्षा करता है। वे मुख्य रूप से मेरे नेटवर्किंग वर्गों (जो असीमित रूप से संचालित होते हैं) में कई WaitFor विधियों (उदा। प्रतीक्षाफोर कनेक्ट) के लिए कोड पुन: उपयोग को कम करने के लिए उपयोग किए जाते हैं। – strager

उत्तर

17

कारण है कि यह काम नहीं करता एक प्रतिनिधि के लिए आवेदन किया + = है जब एक नया प्रतिनिधि जो पुराने और नए का संयोजन है बनाता है। यह मौजूदा प्रतिनिधि को संशोधित नहीं करता है।

इसे काम करने के लिए आपको संदर्भ द्वारा प्रतिनिधि को पास करना होगा।

public static void Helper(ref EventHandler<EventArgs> e) 
{ 
    e+= (x,y) => {}; 
} 

इस विधि के बाहर काम करने का कारण यह है कि एलएचएस अभी भी वास्तविक क्षेत्र है। तो + = एक नया प्रतिनिधि बना देगा और सदस्य क्षेत्र में वापस असाइन करेगा।

+0

दिलचस्प। तो मुझे लगता है + = प्रतिनिधि को पुन: प्रयास करता है (जैसे ई = ई + func)। आपकी सहायताके लिए धन्यवाद! मेरे कोड को डीबग करने की कोशिश करने में कई घंटे बिताए (इसे थ्रेडिंग पर दोष दे रहा है) जब वास्तव में एक घटना को निकाल दिया नहीं जा रहा था। – strager

+0

@strager, जब आप इस तरह की स्थितियों को दबाते हैं, तो प्रतिबिंबित करने के लिए यह एक अच्छा विचार है। यह कुछ भ्रामक वाक्यविन्यास संरचनाओं को अन-हवा देगा और आपको दिखाएगा कि वास्तव में क्या हो रहा है। – JaredPar

+4

रेफरी का उपयोग करने में एक समस्या: यदि मैं हेल्पर (रेफरी myClassInstance.MyEvent) का उपयोग करता हूं तो मुझे निम्न त्रुटि मिलती है: ईवेंट MyEvent केवल + = या - = के बाएं हाथ पर दिखाई दे सकता है (जब MyClass के प्रकार से उपयोग किया जाता है) । मैं इसके आसपास कैसे काम कर सकता हूं? – strager

2

बस अनुमान लगा: आप इसे पारित करने की कोशिश की है रेफरी के रूप में?

public static void MyHelperFunction<TEventArgs>(ref EventHandler<TEventArgs> eventToAttachTo) 

MyHelperFunction(ref MyEvent); 
1

मेरे पास एक समाधान है जहां मेरे पास दो इंटरफेस हैं। पहले इंटरफेस में कुछ घटनाओं को बाध्य करने के तरीके हैं, जबकि अन्य इंटरफ़ेस में ईवेंट विधियां हैं जो उन घटनाओं से बंधी जा सकती हैं।

पहला इंटरफ़ेस की बाइंड विधियां पैरामीटर के रूप में दूसरा इंटरफ़ेस लेती हैं, जिससे किसी भी वर्ग के ईवेंट विधियों को ईवेंट को बाध्य करना संभव हो जाता है जो दूसरे इंटरफ़ेस को लागू करता है।

क्या यह समझ में आता है, या आप कुछ कोड पसंद करेंगे? :)

+1

कोड, कृपया ... –

2

यह बिल्कुल अच्छा नहीं है, लेकिन आप इसे करने के लिए प्रतिबिंब का उपयोग कर सकते हैं।

public EventMonitor(object eventObject, string eventName) 
    { 
     _eventObject = eventObject; 
     _waitEvent = eventObject.GetType().GetEvent(eventName); 

     _handler = new EventHandler(SetEvent); 
     _waitEvent.AddEventHandler(eventObject, _handler); 
    } 

जहां ईवेंट ऑब्जेक्ट ईवेंट वाला ऑब्जेक्ट है, और eventName घटना का नाम है। SetEvent आपका ईवेंट हैंडलर है।

public void Dispose() 
    { 
     _waitEvent.RemoveEventHandler(_eventObject, _handler); 
    } 
+0

क्या आपने इसे काम के रूप में परीक्षण किया है? – Kairan

+0

@ केयरन - मुझे मारता है। यह 3 1/2 साल पहले से अधिक था। – Ray

1

के रूप में कई ने बताया है, एक पद्धति के लिए एक घटना से गुजर रहा है या तो संभव नहीं या सरल नहीं है:

मैं भी इस तरह की एक निपटाने विधि है।

  1. कृपया यह स्पष्ट है, लेकिन मैं अपने इच्छित उपयोग कुछ ऐसी दिखाई देगी संदेह: बस सार्वजनिक रूप से अपने इच्छित जेनेरिक ईवेंट हैंडलर्स सुलभ बनाने के द्वारा

    void Register() 
    { 
        var super = new SuperHandler(); 
    
        //not valid syntax: 
        super.HandleEvent(MyEvent1); 
        super.HandleEvent(MyEvent2); 
        super.HandleEvent(MyEvent3); 
        super.HandleEvent(MyEvent4); 
    } 
    

    आप ऐसा कर सकते हैं (या आंतरिक रूप से, यदि आप चाहें) :

    public static class GenericHandler 
    { 
        public static void HandleAnyEvent(object sender, EventArgs e) 
        { 
         //handle 
        } 
    } 
    
    public class SomeClass 
    { 
        void RegisterEvents() 
        { 
         var r = new EventRaiser(); 
    
         r.ImportantThingHappened += GenericHandler.HandleAnyEvent; 
        } 
    } 
    

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

  2. यदि पंजीकरण तर्क जटिल है या आपको EventHandler निजी रखना चाहिए, तो इंटरफ़ेस ईवेंट का उपयोग करने पर विचार करें। यह कोड की मात्रा को कम करने के आपके इच्छित लक्ष्य को पूरा नहीं कर सकता है, लेकिन यह आपको एक ऐसी कक्षा बनाने की अनुमति देगा जो किसी विशिष्ट प्रकार की सभी घटनाओं को अनुमानित रूप से संभाल सके।

    interface IRaiseEvents 
    { 
        event EventHandler ConnectionCreated; 
        event EventHandler ConnectionLost; 
    } 
    
    public class SuperHandler 
    { 
        void RegisterEvents(IRaiseEvents raiser) 
        { 
         raiser.ConnectionCreated += (sender, args) => Console.WriteLine("Connected."); 
         raiser.ConnectionLost += (sender, args) => Console.WriteLine("Disconnected."); 
        } 
    } 
    
3

बस इस छोटे से सहायक के साथ आया था। यदि यह आपका स्वयं निर्मित कार्यक्रम है तो आप इस तरह एक रैपर का उपयोग कर सकते हैं। आप हैंडलर को सामान्य के रूप में संलग्न करने के लिए अपने + = ऑपरेटरों का उपयोग कर सकते हैं लेकिन आवरण को चारों ओर पास कर सकते हैं और यहां तक ​​कि ईवेंट को कहीं और बढ़ा सकते हैं।

public GenericEvent<EventArgs> MyEvent = new GenericEvent<EventArgs>(); 

संलग्न संचालकों:

MyEvent += (s,e) => {}; 

बढ़ाएं घटना:

public class GenericEvent<T> where T:EventArgs 
{ 
    public event EventHandler<T> Source = delegate { }; 

    public void Raise(object sender, T arg = default(T)) 
    { 
     Source(sender, arg); 
    } 

    public void Raise(T arg = default(T)) 
    { 
     Source(this, arg); 
    } 

    public void AddHandler(EventHandler<T> handler) 
    { 
     Source += handler; 
    } 

    public void RemoveHandler(EventHandler<T> handler) 
    { 
     Source -= handler; 
    } 

    public static GenericEvent<T> operator +(GenericEvent<T> genericEvent, EventHandler<T> handler) 
    { 
     genericEvent.AddHandler(handler); 
     return genericEvent; 
    } 
} 

तरह ईवेंट बनाएं

MyEvent.Raise(); 
+1

एक अच्छी साधारण कक्षा। इसे और अधिक जटिल बनाने के लिए मैं सब्स्क्राइब किए गए ईवेंट की ईवेंट सूची का उपयोग करने का सुझाव दूंगा। जेनेरिकवेन्ट ऑब्जेक्ट का निपटारा होने पर यह सभी सब्स्क्राइब किए गए ईवेंट की सदस्यता रद्द कर देगा। इसका मतलब यह हो सकता है कि जेनेरिकवेन्ट IDISposable इंटरफ़ेस लागू करता है। –

1

तरह पास कुछ कार्रवाई ई = ई => myevent + = ई; और हैंडलर के साथ विधि से कॉल करें? इसे .NET कक्षाओं के साथ काम करने का लाभ है।

+0

आप सही हैं। अगर शायद मुझे इस समस्या से निपटना पड़े तो शायद मैं क्या करूँगा। =] मैंने चार साल पहले (!) सवाल पूछा जब मुझे सी # की कम समझ थी। आपका जवाब जोड़ने के लिए धन्यवाद, यद्यपि; मुझे यकीन है कि यह भविष्य में किसी के लिए सहायक होगा! – strager

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

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