2009-06-01 6 views
5

मेरे पास एक साधारण "समस्या" है जो मुझे लगता है कि मुझे कुछ समाधान मिल गए हैं, लेकिन मुझे यकीन नहीं है कि सी # में सबसे अच्छा अभ्यास करने का तरीका नहीं है।सी # :: इवेंट हैंडलिंग इंटरफ़ेस से प्राप्त घटनाओं या ऑब्जेक्ट्स का संग्रह कब उपयोग करें?

मेरे पास एक मास्टर ऑब्जेक्ट है (एक सिंगलटन कहें) एप्लिकेशन के जीवनकाल के दौरान एक बार instanciated। यह "मास्टर क्लास" नए प्रकार की वस्तुओं का एक गुच्छा बनाता है, हर बार MasterClass.Instance.CreateSlaveObject कहा जाता है, "SlaveClass" कहें।

यह मास्टर क्लास स्टेटस चेंज के लिए किसी अन्य ऑब्जेक्ट पर भी नजर रखता है, और जब ऐसा होता है, तो स्लेव क्लास ऑब्जेक्ट्स को बदलाव के बारे में सूचित करता है। काफी सरल लगता है।

जब से मैं मूल सी ++ दुनिया से आते हैं, जिस तरह से मैंने किया पहले यह एक अंतरफलक

Interface IChangeEventListener 
{ 
    void ChangeHappened(); 
} 

जहाँ से मैं "SlaveClass" व्युत्पन्न है। फिर मेरे "मास्टर क्लास" में मेरे पास है:

... 
IList<IChangeEventListener> slaveList; 
... 
CreateSlaveObject 
{ 
    ... 
    slaveList.Add(slave); 
} 
... 
ChangeHappened() 
{ 
    ... 
    foreach(var slave in slaveList) 
    { 
     slave.ChangeHappened(); 
    } 
} 

और यह काम करता है। लेकिन अगर मैं ऐसा करने का एक और (बेहतर) तरीका हूं तो मैं अपने दिमाग के पीछे सोच रहा था। तो मैंने विषय पर थोड़ा और शोध किया और सी # घटनाओं को देखा।

तो मास्टर क्लास में दासों के संग्रह को बनाए रखने के बजाय, मैं मूल रूप से मास्टर क्लास को स्लेव क्लास (या किसी संपत्ति के माध्यम से) के सीटीआर में इंजेक्ट करता हूं और स्लेव क्लास ऑब्जेक्ट को इवेंट हैंडलर के रूप में चेंजप्पन किया जाता है। इस सचित्र किया जाएगा:

...Master...   
    public delegate void ChangeHappenedDelegate(object sender, NewsInfoArgs args); 
    public event NewUpdateDelegate ChangeHappenedEvent; 
    .... 

    public SlaveClass (MasterClass publisher) //inject publisher service 
    { 
     publisher.ChangeHappenedEvent += ChangeHappened; 
    } 

लेकिन इस दास और मास्टर के बीच एक गैर-आवश्यक युग्मन की तरह प्रतीत हो रहा है, लेकिन मैं प्रदान की निर्माण में ईवेंट सूचना तंत्र की शान की तरह।

तो क्या मुझे अपना वर्तमान कोड रखना चाहिए, या घटना आधारित दृष्टिकोण (प्रकाशक इंजेक्शन के साथ) में जाना चाहिए? और क्यों?

या यदि आप एक वैकल्पिक समाधान का प्रस्ताव दे सकते हैं तो शायद मुझे याद आएगा, मैं भी इसकी सराहना करता हूं।

उत्तर

7

ठीक है, मेरे दिमाग में, आपके जैसे कार्यक्रम और इंटरफेस एक ही सिक्का के दो पक्ष हैं (कम से कम संदर्भ में आपने इसे वर्णित किया है), लेकिन वे वास्तव में पक्ष हैं।

मुझे घटनाओं के बारे में सोचने का तरीका यह है कि "मुझे आपके ईवेंट की सदस्यता लेने की आवश्यकता है क्योंकि मुझे आपको कुछ कहना है जब आपको कुछ कहना होगा"।

जबकि इंटरफ़ेस तरीका है "मुझे आपको यह सूचित करने के लिए एक विधि कॉल करने की आवश्यकता है कि मेरे साथ कुछ हुआ"।

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

ध्यान दें कि यदि आपके दास वर्गों में एक विधि उपलब्ध है जो आपके मास्टर क्लास में कुछ हुआ तो कॉल करने के लिए उपयुक्त होगा, आपको दास वर्ग को इस हुक को जोड़ने के लिए कोड रखने की आवश्यकता नहीं है, आप बस आसानी से कर सकते हैं अपने CreateSlaveClass विधि में ऐसा करते हैं:

SlaveClass sc = new SlaveClass(); 
ChangeHappenedEvent += sc.ChangeHappened; 
return sc; 

यह मूलतः घटना प्रणाली का उपयोग करेगा, लेकिन जाने MasterClass कोड घटनाओं के सभी तारों से करते हैं।

क्या SlaveClass ऑब्जेक्ट्स सिंगलटन क्लास तक लाइव रहता है? यदि नहीं, तो उपरोक्त मामले (मूल रूप से आपके दोनों और मेरा दोनों में) के रूप में, जब आप अपने मास्टर क्लास में उन वस्तुओं का संदर्भ रखते हैं, तो आपको मामले को संभालने की आवश्यकता होती है/अब आवश्यकता नहीं होती है, और इस प्रकार वे कचरा संग्रह के लिए कभी भी योग्य नहीं होगा, जब तक कि आप जबरन उन घटनाओं को हटा दें या इंटरफेस को अनियंत्रित न करें।


, यदि आप एक ही युग्मन समस्या में चलाने के लिए के रूप में आप भी टिप्पणी में उल्लेख किया जा रहे हैं SlaveClass रूप में लंबे समय के रूप में रहने MasterClass नहीं के साथ समस्या को संभालने के लिए।

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

उदाहरण के लिए, इस तरह (और यहाँ मैं एक दृश्य स्टूडियो IntelliSense और एक संकलक के लाभ के बिना टाइप कर रहा हूँ, कृपया इस कोड का अर्थ लेते हैं, और न वाक्य रचना (त्रुटियों)।)

public class WrapperClass 
{ 
    private WeakReference _Slave; 

    public WrapperClass(SlaveClass slave) 
    { 
     _Slave = new WeakReference(slave); 
    } 

    public WrapperClass.ChangeHappened() 
    { 
     Object o = _Slave.Target; 
     if (o != null) 
      ((SlaveClass)o).ChangeHappened(); 
     else 
      MasterClass.ChangeHappenedEvent -= ChangeHappened; 
    } 
} 
अगली कॉल

SlaveClass sc = new SlaveClass(); 
WrapperClass wc = new WrapperClass(sc); 
ChangeHappenedEvent += wc.ChangeHappened; 
return sc; 

एक बार SlaveClass वस्तु इकट्ठा किया जाता है, (नहीं जल्दी ही है कि तुलना में, लेकिन) ईवेंट हैंडलर्स करने के लिए अपने MasterClass से उनमें से सूचित करने के लिए:

अपने MasterClass में, आप कुछ इस तरह करना होगा इस प्रकार बदलें, उन सभी रैपर जो अब ऑब्जेक्ट नहीं करेंगे हटाया जाना।

+0

साफ! मुझे वास्तव में मास्टरक्लस के इवेंट हुकिंग की देखभाल करने के लिए प्रस्तावित दृष्टिकोण पसंद है, लेकिन घटनाओं के तंत्र को ध्यान में रखते हुए :) जैसा कि मैंने देखा है, जैसा समस्या मैंने देखी है, इस बात की कोई गारंटी नहीं है कि स्लेव मास्टर के रूप में तब तक जीवित रहेगा ... इसलिए यदि मैं स्लेव विनाशक में घटना को अनदेखा करना चाहता हूं, तो मैं युग्मन वापस लाऊंगा:/ – Futurist

+0

ठीक है, एक विकल्प है, मुझे अपना जवाब बदलने दो। –

+0

इंडिपथ उत्तर के लिए धन्यवाद। मैं इस पर विचार करूंगा क्योंकि कुछ अवधारणाएं हैं (जैसे कमजोर पड़ने) जो अभी भी मुझसे अपरिचित हैं। – Futurist

0

मुझे लगता है कि यह सिर्फ व्यक्तिगत वरीयता का मामला है ... व्यक्तिगत रूप से मैं घटनाओं का उपयोग करना पसंद करता हूं, क्योंकि यह .NET "दर्शन" में बेहतर फिट बैठता है।

आपके मामले में, अगर MasterClass एक सिंगलटन है, तो आप, SlaveClass के निर्माता के लिए इसे पारित करने के बाद से यह सिंगलटन संपत्ति (या विधि) का उपयोग कर प्राप्त किए जा सकें की जरूरत नहीं है:

public SlaveClass() 
{ 
    MasterClass.Instance.ChangeHappenedEvent += ChangeHappened; 
} 
+0

मैंने थोड़ा सा झूठ बोला..यह वास्तव में सिंगलटन नहीं है :) लेकिन मुझे अभी भी यह पसंद नहीं है कि दास को गुरु के बारे में पता होना चाहिए, भले ही मास्टर एक सिंगलटन होता। फिर भी जवाब के लिए धन्यवाद। – Futurist

0

जैसा कि आपको मास्टर क्लास का सिंगलटन उदाहरण दिखाई देता है, क्यों MasterClass.Instance.ChangeHappenedEvent की सदस्यता लें? यह अभी भी एक तंग-आश युग्मन है, लेकिन अपेक्षाकृत साफ है।

+0

मैंने थोड़ा सा झूठ बोला..यह वास्तव में सिंगलटन नहीं है :) लेकिन मुझे अभी भी यह पसंद नहीं है कि दास को गुरु के बारे में पता होना चाहिए, भले ही मास्टर एक सिंगलटन होता। फिर भी जवाब के लिए धन्यवाद। – Futurist

0

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

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

एक वैकल्पिक दृष्टिकोण जो वीक रेफरेंस ऑब्जेक्ट्स को कम करने से बचने के लिए अक्सर होता है, अक्सर सार्वजनिक "दास" वस्तु एक निजी वस्तु के लिए एक रैपर होनी चाहिए, और सार्वजनिक वस्तु को ओवरराइड करना निजी वस्तु को यह जानने के लिए अंतिम रूप देना चाहिए इसके बाहर कोई बाहरी संदर्भ मौजूद नहीं है। इसके लिए ऑब्जेक्ट में सार्वजनिक पहुंच के लिए एक मजबूत स्तर का मजबूत संकेत जोड़ने की आवश्यकता होगी, लेकिन यह छोड़ने से बच जाएगा - यहां तक ​​कि क्षणिक रूप से - त्याग किए गए ऑब्जेक्ट्स के मजबूत संदर्भ।

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