2011-02-22 20 views
11

अगर मैं एक कोड है कि कुछ इस तरह दिखता है:क्या मुझे स्थानीय चर के अज्ञात ईवेंट हैंडलर से सदस्यता समाप्त करनी है?

public void Foo() 
{ 
    Bar bar = new Bar(); 

    bar.SomeEvent += (sender, e) => 
    { 
     //Do something here 
    }; 

    bar.DoSomeOtherThingAndRaiseSomeEvent(); 
} 

एकत्र किया जा bar करेंगे जब विधि क्षेत्र से बाहर चलाता है, या मैं एक स्मृति रिसाव की वजह से रोकने के लिए मैन्युअल रूप से घटना से सदस्यता समाप्त करना होगा SomeEvent का संदर्भ?

उत्तर

18

आपकी स्थिति ठीक है; घटना ग्राहकप्रकाशक को एकत्रित होने से नहीं रोकेगा, लेकिन विपरीत हो सकता है।

उदाहरण के लिए,

class Foo 
{ 
    public event EventHandler FooEvent; 

    void LeakMemory() 
    { 
     Bar bar = new Bar(); 

     bar.AttachEvent(this); 
    } 
} 

class Bar 
{ 
    void AttachEvent(Foo foo) 
    { 
     foo.FooEvent += (sender, e) => { }; 
    } 
} 

इस मामले में, LeakMemory में बनाई गई Bar के कहने जब तक या तो

  • गुमनाम विधि लैम्ब्डा द्वारा प्रतिनिधित्व FooEvent से निकाल दिया जाता एकत्र नहीं किया जा सकता ' एस आमंत्रण सूची
  • फू का उदाहरण जिस पर इसे संलग्न किया गया है

ऐसा इसलिए है क्योंकि घटना (जो सामान्य delegate उदाहरण पर केवल कुछ वाक्य रचनात्मक चीनी है) प्रतिनिधियों की एक सूची पर आती है जब इसे बुलाया जाता है, और इन प्रतिनिधियों में से प्रत्येक ने ऑब्जेक्ट का संदर्भ दिया है कि यह जुड़ा हुआ है (इस मामले में, Bar का उदाहरण)।

ध्यान दें कि हम केवल संग्रह पात्रता संग्रह के बारे में बात कर रहे हैं। सिर्फ इसलिए कि यह योग्य है के बारे में कुछ भी नहीं कहता है जब (या यहां तक ​​कि, वास्तव में, यदि) यह एकत्र किया जाएगा, बस हो सकता है।

+0

वहाँ किसी भी मानक फार्म/"कमजोर संदर्भ घटनाओं" का मुहावरा है: हालांकि यह तार के विपरीत वे अर्थ की दृष्टि से जब समानता का निर्धारण करने की तुलना में नहीं हैं, क्योंकि lambdas "समारोह शाब्दिक" कर रहे हैं, एक तरह से स्ट्रिंग शाब्दिक की तरह? –

+0

@pst: दुर्भाग्य से, नहीं। यह ऐसा कुछ है जिस पर पहले चर्चा की गई है (अधिक आम तौर पर, उन संदर्भों पर विचार न करें जो * केवल * प्रतिनिधियों का हिस्सा पहुंचने योग्य हैं), लेकिन जटिलताओं और संभावित नुकसान ने इसे अब तक लागू करने से रोका है। आखिरी बार देखे जाने के बाद से उन योजनाओं में बदलाव हो सकते हैं, लेकिन जहां तक ​​मुझे पता है कि चीजें खड़ी हैं और जारी रहेगी। यहां तक ​​कि 'WeakReference' क्लास का उपयोग करने वाले समाधान भी इस मुद्दे को किसी अन्य प्रकार पर ले जाते हैं। –

1

ठीक है, वस्तु bar संदर्भित करता है स्वचालित रूप से कचरा एकत्र तुरंत नहीं होगा ... यह है कि अभी bar चर इसे से किया जा रहा कचरा एकत्र को रोकने नहीं होगा।

ईवेंट हैंडलर कचरा एकत्र किया जा रहा से Bar के कहने पर रोक नहीं लगेगी या तो यद्यपि - "सामान्य" समस्या है एक ईवेंट हैंडलर कचरा एकत्र (अगर यह एक उदाहरण का उपयोग करता जा रहा से एक घटना का ग्राहक रहता है कि किसी अज्ञात फ़ंक्शन में "यह" विधि या कैप्चर करें)। यह आम तौर पर प्रकाशक को कचरा एकत्रित नहीं करता है। बस याद रखें कि प्रकाशक को सभी ग्राहकों के लिए संदर्भ रखने की आवश्यकता है - ग्राहक को यह याद रखने की आवश्यकता नहीं है कि उसने क्या सब्सक्राइब किया है, जब तक कि यह स्पष्ट रूप से सदस्यता समाप्त नहीं करना चाहता या बाद में किसी अन्य सदस्य का उपयोग नहीं करना चाहता।

कुछ और नहीं मानना ​​Bar जीवित रहने का आपका उदाहरण रख रहा है, आपका कोड ठीक होना चाहिए।

1

उपर्युक्त उत्तर सही हैं; मैं बस एक नोट बनाना चाहता था। हैंडलर के रूप में उपयोग किए जाने वाले बेनामी प्रतिनिधियों को केवल सदस्यता समाप्त कर दिया जा सकता है यदि आप प्रतिनिधि/लैम्ब्डा के लिए कुछ अन्य संदर्भ बनाए रखते हैं।

public event EventHandler MyEvent; 

... 

//adds a reference to this named method in the context of the current instance 
MyEvent += Foo; 

//Adds a reference to this anonymous function literal to MyEvent 
MyEvent += (s,e) => Bar(); 

... 

//The named method of the current instance will be the same reference 
//as the named method. 
MyEvent -= Foo; 

//HOWEVER, even though this lambda is semantically equal to the anonymous handler, 
//it is a different function literal and therefore a different reference, 
//which will not match the anonymous handler. 
MyEvent -= (s,e) => Bar(); 

var hasNoHandlers = MyEvent == null; //false 

//To successfully unsubscribe a lambda, you have to keep a reference handy: 

EventHandler myHandler = (s,e) => Bar(); 

MyEvent += myHandler; 

... 

//the variable holds the same reference we added to the event earlier, 
//so THIS call will remove the handler. 
MyEvent -= myHandler; 
संबंधित मुद्दे

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