2011-03-04 9 views
5

अगर मैं एक .NET वर्ग जो इस तरह एक गुमनाम समारोह के साथ एक घटना का सदस्य बनता बनाएँ:क्या मुझे इस तरह के इवेंट हैंडलर को हटाने की ज़रूरत है?

void MyMethod() 
{ 
    Application.Current.Deactivated += (s,e) => { ChangeAppearance(); }; 
} 

इस ईवेंट हैंडलर एक रूट की जा रही कचरा एकत्र से मेरी कक्षा रखने होगा?

यदि नहीं, तो वाह! लेकिन यदि हां, तो क्या आप मुझे हटाने वाक्यविन्यास दिखा सकते हैं? बस एक ही कोड के साथ - = गलत लगता है।

उत्तर

3

आप एक 'असली' विधि का उपयोग या तो कर सकते हैं साइमन डी पता चलता है के रूप में, या ऐसा करते हैं: के बाद से यह कुछ हद तक बदसूरत है और एक लैम्ब्डा का उपयोग कर लधु होने के लिए करने के उद्देश्य धरा

EventHandler handler = null; 
handler = (s,e) => { 
    Application.Current.Deactivated -= handler; 
    ChangeAppearance(); 
}; 
Application.Current.Deactivated += handler; 

, मैं d शायद इसे एक विधि के लिए refactoring के साथ जाओ। लेकिन यह जानना उपयोगी है कि और क्या काम करता है।

चेतावनी: यह करते हुए कहा कि आप सुपर अल्ट्रा handler बिल्कुल बिंदु है जहां आप ईवेंट और बिंदु जहां यह वास्तव में शुरू हो जाती है की सदस्यता के बीच के मूल्य के साथ गड़बड़ नहीं करने के लिए सावधान रहना होगा कि बिना चला जाता है अन्यथा सदस्यता रद्द करने का हिस्सा सही ढंग से काम नहीं करेगा।

+0

मुझे यहां succint शैली पसंद है। मेरी जरूरतों के लिए, यह पूरी तरह से काम करना चाहिए। इसे लिखने के लिए समय निकालने के लिए धन्यवाद! – jschroedl

3

मुझे लगता है कि आपको सदस्यता समाप्त करने की आवश्यकता है, क्योंकि ईवेंट प्रदाता (एप्लिकेशन) रहता है - या कम से कम आपके उपभोक्ता से अधिक समय तक जीवित रह सकता है। तो प्रत्येक सब्सक्राइबिंग उदाहरण मर रहा है जबकि ऐप रहता है मेमोरी लीक बना देगा।

आप ईवेंट में एक अनाम प्रतिनिधि सदस्यता ले रहे हैं। यही कारण है कि आप इसे उसी तरह से सदस्यता नहीं ले सकते हैं, क्योंकि आप इसे अब संबोधित नहीं कर सकते हैं। असल में आप उसी पल में विधि बना रहे हैं जिस पर आप सब्सक्राइब करते हैं, और आप किसी भी पॉइंटर को नव निर्मित विधि में स्टोर नहीं करते हैं।

Application.Current.Deactivated += ChangeAppearance; 
Application.Current.Deactivated -= ChangeAppearance; 
private void ChangeAppearance(object sender, EventArgs eventArgs) 
{ 
    throw new NotImplementedException(); 
} 
+0

संदेह को स्वीकार करने के लिए धन्यवाद। -जॉन – jschroedl

1

यह वास्तव में एक रिसाव कि कचरा संग्रहण से बचाता है:

आप थोड़ा अपने कार्यान्वयन एक 'असली' विधि का उपयोग करने को बदलते हैं, तो आप आसानी से घटना से एक ही तरह से आप इसे करने के लिए सदस्यता सदस्यता समाप्त कर सकते हैं। इसके आस-पास के तरीके हैं - वीक रेफरेंस बेहतर लोगों में से एक है।

This link में आपके लिए अच्छी बातचीत और अच्छे उत्तर हैं।

+0

सूचक के लिए धन्यवाद। वे लोग इस में सुंदर हो जाते हैं !! – jschroedl

2

आपको निश्चित रूप से संदर्भ को साफ़ करना होगा। यदि कोई संदेह था तो आप आसानी से अपने स्वयं के स्थिर घटना के साथ परीक्षण कर सकते हैं।

static class MemoryLeak 
{ 
    static List<Action<int>> list = new List<Action<int>>(); 
    public static event Action<int> ActivateLeak 
    { 
     add 
     { 
      list.Add(value); 
     } 
     remove 
     { 
      list.Remove(value); 
     } 
    } 
} 

फिर निकालें फ़ंक्शन में ब्रेकपॉइंट सेट करके आप देख सकते हैं कि आपका संदर्भ साफ़ नहीं है।

class Program 
{ 
    static void Main(string[] args) 
    { 
     foo f = new foo(); 
     MemoryLeak.ActivateLeak += o => f.bar(); 
     f.tryCleanup(); 
    } 
} 

class foo 
{ 
    public void bar() 
    { } 

    public void tryCleanup() 
    { 
     MemoryLeak.ActivateLeak -= o => bar(); 
    } 
} 

साइमन के समाधान के विकल्प के रूप में आप "अलग" क्रिया बनाने के लिए दूसरे बंदरगाह का उपयोग कर सकते हैं जिसे पारित किया जा सकता है।

foo f = new foo(); 
Action<int> callfoo = o => f.bar(); 
MemoryLeak.ActivateLeak += callfoo; 
Action cleanUp =() => MemoryLeak.ActivateLeak -= callfoo; 

// Now you can pass around the cleanUp action and call it when you need to unsubscribe from the event. 
cleanUp(); 
संबंधित मुद्दे