2010-11-13 30 views
27

मैं है 3 प्रश्न के विषय में घटनाओं:क्या मुझे घटनाओं से सदस्यता छोड़नी चाहिए?

  1. मैं हमेशा सदस्यता समाप्त घटनाओं सदस्यता ले रखी थी कि करना चाहिए?
  2. यदि मैं नहीं करता तो क्या होता है?
  3. नीचे दिए गए उदाहरणों में, आप सब्स्क्राइब किए गए ईवेंट से कैसे सदस्यता रद्द करेंगे?

मैं उदाहरण के लिए इस कोड है:

ctor: उद्देश्य: डेटाबेस संपत्ति अपडेट

this.PropertyChanged += (o, e) => 
{ 
    switch (e.PropertyName) 
    { 
     case "FirstName": break; 
     case "LastName": break; 
    } 
}; 

के लिए और इस: उद्देश्य: जीयूआई बाध्यकारी ViewModels में मॉडल लपेट के लिए

ObservableCollection<Period> periods = _lpRepo.GetDailyLessonPlanner(data.DailyDate); 
PeriodListViewModel = new ObservableCollection<PeriodViewModel>(); 

foreach (Period period in periods) 
{ 
    PeriodViewModel periodViewModel = new PeriodViewModel(period,_lpRepo); 
    foreach (DocumentListViewModel documentListViewModel in periodViewModel.DocumentViewModelList) 
    { 
     documentListViewModel.DeleteDocumentDelegate += new Action<List<Document>>(OnDeleteDocument); 
     documentListViewModel.AddDocumentDelegate += new Action(OnAddDocument); 
     documentListViewModel.OpenDocumentDelegate += new Action<int, string>(OnOpenDocument); 
    } 
    PeriodListViewModel.Add(periodViewModel); 
} 
+0

http: // stackoverflow।कॉम/प्रश्न/1061727/is-it-bad-to-not-unregister-event-handlers – SwDevMan81

उत्तर

23

1) यह निर्भर करता है। आम तौर पर यह एक अच्छा विचार है, लेकिन ऐसे सामान्य मामले हैं जहां आपको आवश्यकता नहीं है। असल में, यदि आप सुनिश्चित हैं कि सब्सक्राइबिंग ऑब्जेक्ट ईवेंट स्रोत से बाहर निकलने जा रहा है, तो आपको सदस्यता समाप्त करनी चाहिए, अन्यथा यह एक अनावश्यक संदर्भ बनाएगा।

यदि फिर भी अपने वस्तु निम्नलिखित में की तरह अपनी ही घटनाओं की सदस्यता है,:

<Window Loaded="self_Loaded" ...>...</Window> 

आप की जरूरत नहीं है --then।

2) किसी ईवेंट की सदस्यता लेने से सदस्यता लेने वाले ऑब्जेक्ट का अतिरिक्त संदर्भ मिलता है। इसलिए यदि आप सदस्यता समाप्त नहीं करते हैं, तो आपकी ऑब्जेक्ट को इस संदर्भ से जीवंत रखा जा सकता है, जिससे प्रभावी रूप से मेमोरी रिसाव हो जाता है। सदस्यता रद्द करके आप उस संदर्भ को हटा रहे हैं। ध्यान दें कि स्व-सदस्यता के मामले में समस्या उत्पन्न नहीं होती है।

3) आप इस तरह कर सकते हैं:

this.PropertyChanged += PropertyChangedHandler; 
... 
this.PropertyChanged -= PropertyChangedHandler; 

जहां

void PropertyChangedHandler(object o, PropertyChangedEventArgs e) 
{ 
    switch (e.PropertyName) 
    { 
     case "FirstName": break; 
     case "LastName": break; 
    } 
} 
+0

जब मैं आपके निचले कोड का उपयोग करता हूं तो मैं संकलित नहीं कर सकता? मैंने एक ";" रखा आखिरी "}" के पीछे लेकिन यह संकलन नहीं कर रहा है? और मुझे आपके सुझाए गए कोड से कहां सदस्यता लेनी चाहिए? – Elisabeth

+0

@ लिसा: (1) आपको प्राप्त त्रुटि संदेश क्या है? (2) जब आपको घटनाओं की आवश्यकता नहीं होती है तो आपको सदस्यता समाप्त करनी चाहिए। अक्सर यह आपके ऑब्जेक्ट के जीवनकाल के अंत में होता है। यदि आप ऐसी वस्तु के बारे में अधिक बता सकते हैं जो घटनाओं की सदस्यता ले रहा है, तो यह समझना आसान होगा कि सदस्यता समाप्त करने के लिए कब करना है। – Vlad

+0

उपरोक्त मेरे कोड की जांच करें मैं 3 घटनाओं पर XXXXX सब्सक्राइब करता हूं। एक PeriodViewModel दस्तावेज़ दस्तावेज़ ViewModel को न तो हटाया जा सकता है। – Elisabeth

4

आप एमएसडीएन पर this article पर एक नज़र डाल सकते हैं। उद्धरण:

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

1

1.) मैं हमेशा desubscribe घटनाओं सदस्य थे, करना चाहिए?
आमतौर पर हाँ।एकमात्र अपवाद तब होता है जब आप जिस ऑब्जेक्ट पर सब्सक्राइब करते हैं उसे संदर्भित नहीं किया जाता है और जल्द ही कचरा इकट्ठा किया जाएगा।

2.) यदि मैं नहीं करता तो क्या होता है?
जिस ऑब्जेक्ट पर आपने सदस्यता ली है वह प्रतिनिधि के लिए एक संदर्भ रखेगी, जो बदले में इसके this पॉइंटर का संदर्भ रखती है, और इस प्रकार आपको मेमोरी रिसाव मिल जाएगा।
या यदि हैंडलर लम्दा था तो यह जो भी स्थानीय चर है, उसे पकड़ लेगा, जो इस प्रकार एकत्र नहीं किया जाएगा।

+1

मैं इंगित करता हूं कि यदि आप ईवेंट की सदस्यता समाप्त नहीं करते हैं तो ऑब्जेक्ट का उपयोग करके समाप्त होने के बाद आपके हैंडलर को कॉल किया जा सकता है; यदि वस्तु का निपटान करने के बाद ऑब्जेक्ट डिस्पोजेबल है। इससे हैंडलर कोड पर इसका असर हो सकता है यदि यह अप्रबंधित संसाधनों का उपयोग करता है जो निपटान द्वारा जारी किए गए हैं। –

39

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

अब आपको वास्तव में सदस्यता समाप्त करने की आवश्यकता है या नहीं, यह घटना निर्माता और घटना उपभोक्ता के बीच संबंधों पर निर्भर करता है। यदि ईवेंट निर्माता को उपभोक्ता उपभोक्ता से अधिक समय तक जीना चाहिए, तो आप सदस्यता समाप्त कर सकते हैं - क्योंकि अन्यथा निर्माता का उपभोक्ता का संदर्भ होगा, इसे जीवित रखने के लिए लंबे समय तक जीवित रखना चाहिए। जब तक निर्माता इसे उत्पादित करता है तब तक ईवेंट हैंडलर भी कॉलिंग जारी रखेगा।

अब कई मामलों में यह कोई समस्या नहीं है - उदाहरण के लिए, एक फॉर्म में Click ईवेंट उठाए जाने वाले बटन के बारे में तब तक रहने की संभावना है जब तक यह फ़ॉर्म बनाया गया हो, जहां हैंडलर आमतौर पर सदस्यता लेता है .. इसलिए सदस्यता समाप्त करने की कोई आवश्यकता नहीं है। यह एक जीयूआई के लिए बहुत आम है।

इसी तरह यदि आप एक ही अतुल्यकालिक अनुरोध के प्रयोजन के लिए एक WebClient केवल बनाने के लिए, प्रासंगिक घटना की सदस्यता और अतुल्यकालिक अनुरोध प्रारंभ करें, फिर WebClient ही कचरा संग्रहण जब अनुरोध समाप्त हो गया है के लिए पात्र होगा (यदि आप यह सोचते हैं डॉन कहीं और संदर्भ नहीं रखेंगे)।

असल में, आपको हमेशा निर्माता और उपभोक्ता के बीच संबंधों पर विचार करना चाहिए। यदि निर्माता उपभोक्ता को या से अधिक समय तक जीवित रहने जा रहा है, तो यह उस घटना को बढ़ाने के लिए जारी रहेगा जब आप इसमें रुचि नहीं रखते हैं, तो आपको सदस्यता समाप्त करनी चाहिए।

+0

घटना निर्माता = documentListViewModel? घटना उपभोक्ता = उपरोक्त से एक ऑनऑक्स-विधि? आपका मतलब है कि अगर मैं एक दस्तावेज़ को हटाने जा रहा हूं ListViewModel अभी भी OnXXX-method का संदर्भ है? ViewModel में ईवेंट से मुझे कहां से सदस्यता लेनी चाहिए? – Elisabeth

2

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

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

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

डब्ल्यूपीएफ एक अपवाद है क्योंकि इसमें एक कमजोर घटना मॉडल है जहां कमजोर संदर्भों का उपयोग करने के लिए घटनाओं की सदस्यता ली जाती है और यह स्मृति में फॉर्म को नहीं रखेगी। हालांकि, जब भी आप फॉर्म का हिस्सा नहीं हैं, तब भी सदस्यता समाप्त करना सबसे अच्छा अभ्यास है।

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