आप अपनी सभी कक्षाओं में आईडीसिस को फैलने से कैसे रोकें?


138

इन सरल कक्षाओं से शुरू करें ...

मान लीजिए कि मेरे पास कक्षाओं का एक सरल सेट है:

class Bus
{
    Driver busDriver = new Driver();
}

class Driver
{
    Shoe[] shoes = { new Shoe(), new Shoe() };
}

class Shoe
{
    Shoelace lace = new Shoelace();
}

class Shoelace
{
    bool tied = false;
}

A के Busपास a है Driver, Driverदो Shoes है, प्रत्येक के Shoeपास a है Shoelace। सब बहुत मूर्खतापूर्ण।

Shoelace के लिए एक IDisposable ऑब्जेक्ट जोड़ें

बाद में मैंने फैसला किया कि कुछ ऑपरेशन Shoelaceमल्टी-थ्रेडेड हो सकते हैं, इसलिए मैं EventWaitHandleथ्रेड्स के साथ संवाद करने के लिए जोड़ता हूं । तो Shoelaceअब ऐसा दिखता है:

class Shoelace
{
    private AutoResetEvent waitHandle = new AutoResetEvent(false);
    bool tied = false;
    // ... other stuff ..
}

Shoelace पर आईडिसोपल लागू करें

लेकिन अब Microsoft का FxCop शिकायत करेगा: "'Shoelace' पर IDisposable को लागू करें क्योंकि यह निम्नलिखित IDisposable प्रकारों के सदस्य बनाता है: 'EventWaitHandle'।"

ठीक है, मैं इस IDisposableपर अमल करता Shoelaceहूं और मेरा साफ-सुथरा छोटा वर्ग यह भयानक गड़बड़झाला बन जाता है:

class Shoelace : IDisposable
{
    private AutoResetEvent waitHandle = new AutoResetEvent(false);
    bool tied = false;
    private bool disposed = false;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~Shoelace()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                if (waitHandle != null)
                {
                    waitHandle.Close();
                    waitHandle = null;
                }
            }
            // No unmanaged resources to release otherwise they'd go here.
        }
        disposed = true;
    }
}

या (के रूप में टिप्पणीकर्ताओं द्वारा बताया) के बाद से Shoelaceही कोई अप्रबंधित संसाधन उपलब्ध हैं, मैं जरूरत के बिना सरल निपटाने कार्यान्वयन का उपयोग हो सकता है Dispose(bool)और नाशक:

class Shoelace : IDisposable
{
    private AutoResetEvent waitHandle = new AutoResetEvent(false);
    bool tied = false;

    public void Dispose()
    {
        if (waitHandle != null)
        {
            waitHandle.Close();
            waitHandle = null;
        }
        GC.SuppressFinalize(this);
    }
}

डरावने रूप में देखो के रूप में IDisposable फैलता है

ठीक है कि तय है। लेकिन अब FxCop शिकायत करेगा जो Shoeएक बनाता है Shoelace, इसलिए भी Shoeहोना चाहिए IDisposable

और Driverबनाता है Shoeतो Driverहोना ही चाहिए IDisposable। और Busबनाता है Driverतो Busहोना चाहिए IDisposableऔर इतने पर।

अचानक मेरे छोटे परिवर्तन से Shoelaceमुझे बहुत काम मिल रहा है और मेरे बॉस सोच रहे हैं कि मुझे Busबदलाव करने के लिए चेकआउट करने की आवश्यकता क्यों है Shoelace

प्रश्न

आप इस प्रसार को कैसे रोक सकते हैं IDisposable, लेकिन फिर भी यह सुनिश्चित करें कि आपकी अप्रबंधित वस्तुएं ठीक से निपटें?


9
असाधारण रूप से अच्छा सवाल है, मेरा मानना ​​है कि उत्तर उनके उपयोग को कम करता है और उच्च स्तर के आईडीसपोज़ीबल्स को कम से कम उपयोग करने के साथ रखने की कोशिश करता है, लेकिन यह हमेशा संभव नहीं होता है (विशेष रूप से जहां उन आईडीसपॉज़ेबल्स C ++ dlls या समान के साथ इंटरोप के कारण होते हैं)। जवाब के लिए fwd देखो।
अन्नकूट

ठीक है डैन, मैंने शोलैस पर आईडीसोपायरी को लागू करने के दोनों तरीकों को दिखाने के लिए सवाल अपडेट किया है।
ग्राहम

मैं आमतौर पर मेरी रक्षा के लिए अन्य वर्गों के कार्यान्वयन विवरणों पर भरोसा करने से सावधान रहता हूं। कोई बात नहीं अगर मैं आसानी से इसे रोक सकता हूँ। शायद मैं ज्यादा सतर्क हूं या शायद मैं एक सी प्रोग्रामर के रूप में बहुत लंबा समय बिता चुका हूं, लेकिन मैं आयरिश तरीका
अपनाऊंगा

@Dan: शून्य चेक को अभी भी यह सुनिश्चित करने की आवश्यकता है कि ऑब्जेक्ट स्वयं को अशक्त करने के लिए सेट नहीं किया गया है, इस स्थिति में प्रतीक्षा करने के लिए कॉल। Dandpose () एक NullReferenceException को फेंक देगा।
स्कॉट डॉर्मन

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

जवाबों:


36

आप वास्तव में आईडीइज़्रोपी को फैलने से नहीं रोक सकते। कुछ वर्गों को निपटाया जाना चाहिए, जैसे AutoResetEvent, और सबसे प्रभावी तरीका यह है कि इसे Dispose()अंतिम रूप से ओवरहेड से बचने के लिए विधि में किया जाए। लेकिन इस विधि को किसी भी तरह से कॉल किया जाना चाहिए, इसलिए आपके उदाहरण में बिल्कुल वैसा ही वर्ग जो एनकैप्सुलेट करता है या जिसमें इनको डिस्पोज करना होता है, इसलिए उन्हें डिस्पोजेबल होना चाहिए, साथ ही इससे बचने का एकमात्र तरीका है:

  • जहाँ संभव हो, आईडीसॉपी कक्षाओं का उपयोग करने से बचें, एकल स्थानों में घटनाओं के लिए लॉक या प्रतीक्षा करें, एकल स्थान पर महंगे संसाधन रखें, आदि
  • उन्हें केवल तब ही बनाएं जब आपको उनकी आवश्यकता हो और बस ( usingपैटर्न) के बाद उनका निपटान करें

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


4
सलाह है कि आप इसे अनदेखा कर सकते हैं क्योंकि कार्यान्वयन आज कुछ भी बुरा नहीं है, क्योंकि भविष्य का संस्करण वास्तव में डिस्पोज़ में कुछ महत्वपूर्ण कर सकता है, और अब आपको लीक को ट्रैक करने के लिए एक मुश्किल मिल गई है।
एंडी

1
"महंगे संसाधनों को रखें", आईडीसॉरोपी आवश्यक रूप से महंगे नहीं हैं, वास्तव में यह उदाहरण जो एक प्रतीक्षा प्रतीक्षा का उपयोग करता है, वह एक "हल्के वजन" के बारे में है जैसा कि आप प्राप्त करते हैं।
अंकन

20

शुद्धता के संदर्भ में, आप एक वस्तु संबंध के माध्यम से आईडीसिसोप्लिक के प्रसार को रोक नहीं सकते हैं यदि कोई मूल वस्तु बनाता है और अनिवार्य रूप से एक बाल वस्तु का मालिक है जिसे अब डिस्पोजेबल होना चाहिए। FxCop इस स्थिति में सही है और माता-पिता को IDisposable होना चाहिए।

आप जो कुछ भी कर सकते हैं, वह अपनी वस्तु पदानुक्रम में एक पत्ता वर्ग के लिए एक आईडीसोपॉली जोड़ने से बचना है। यह हमेशा एक आसान काम नहीं है, लेकिन यह एक दिलचस्प अभ्यास है। तार्किक दृष्टिकोण से, कोई कारण नहीं है कि एक शूलेस को डिस्पोजेबल होने की आवश्यकता है। यहाँ एक WaitHandle जोड़ने के बजाय, क्या यह उपयोग किए जाने वाले बिंदु पर एक FootLace और एक WaitHandle के बीच जुड़ाव संभव है। सबसे आसान तरीका एक शब्दकोश उदाहरण के माध्यम से है।

यदि आप WaitHandle को एक ढीली संगति में ले जा सकते हैं, तो उस बिंदु पर एक MapHandle वास्तव में उपयोग किया जाता है, तो आप इस श्रृंखला को तोड़ सकते हैं।


2
वहां एसोसिएशन बनाना बहुत अजीब लगता है। यह AutoResetEvent Shoelace कार्यान्वयन के लिए निजी है, इसलिए इसे सार्वजनिक रूप से उजागर करना मेरी राय में गलत होगा।
ग्राहम

@ ग्राहम, मैं यह नहीं कह रहा हूं कि इसे सार्वजनिक रूप से उजागर करें। मैं कह रहा हूं कि इसे उस स्थान पर ले जाया जा सकता है जहां शूलेस बंधे हैं। शायद अगर जूता लेस बांधना एक ऐसा जटिल काम है, तो उन्हें एक शॉलेयर टियर क्लास होना चाहिए।
जारेदपार

1
क्या आप कुछ कोड स्निपेट JaredPar के साथ अपने उत्तर का विस्तार कर सकते हैं? मैं अपने उदाहरण को थोड़ा बढ़ा सकता हूं, लेकिन मैं कल्पना कर रहा हूं कि Shoelace बनाता है और Tyer धागा शुरू करता है, जो प्रतीक्षा में प्रतीक्षा कर रहा है। WitOne।
ग्राहम

1
इस पर +1। मुझे लगता है कि यह अजीब होगा कि सिर्फ शॉएलेस को समवर्ती कहा जाएगा, लेकिन अन्य लोगों को नहीं। सोचो कि कुल जड़ क्या होनी चाहिए। इस मामले में यह बस, IMHO होना चाहिए, हालांकि मैं डोमेन से अपरिचित हूं। तो, उस स्थिति में, बस में वेटहैंडल शामिल होना चाहिए और बस के खिलाफ सभी ऑपरेशन और यह सभी बच्चों को सिंक्रनाइज़ किया जाएगा।
जोहान्स गुस्ताफसन

16

IDisposableफैलने से रोकने के लिए , आपको एक एकल विधि के अंदर एक डिस्पोजेबल ऑब्जेक्ट के उपयोग को एनकोड करने का प्रयास करना चाहिए। Shoelaceअलग तरीके से डिजाइन करने की कोशिश करें :

class Shoelace { 
  bool tied = false; 

  public void Tie() {

    using (var waitHandle = new AutoResetEvent(false)) {

      // you can even pass the disposable to other methods
      OtherMethod(waitHandle);

      // or hold it in a field (but FxCop will complain that your class is not disposable),
      // as long as you take control of its lifecycle
      _waitHandle = waitHandle;
      OtherMethodThatUsesTheWaitHandleFromTheField();

    } 

  }
} 

प्रतीक्षा हैंडल का दायरा Tieविधि तक सीमित है , और वर्ग को डिस्पोजेबल फ़ील्ड की आवश्यकता नहीं है, और इसलिए इसे स्वयं उपयोग करने की आवश्यकता नहीं होगी।

चूंकि वेट हैंडल एक इंप्लीमेंटेशन डिटेल है Shoelace, जिसके अंदर , यह किसी भी तरह से इसके पब्लिक इंटरफेस में नहीं बदलना चाहिए, जैसे कि इसकी घोषणा में एक नया इंटरफ़ेस जोड़ना। तब क्या होगा जब आपको किसी डिस्पोजेबल क्षेत्र की आवश्यकता नहीं है, क्या आप IDisposableघोषणा को हटा देंगे ? यदि आप Shoelace अमूर्तता के बारे में सोचते हैं , तो आप जल्दी से महसूस करते हैं कि इसे बुनियादी सुविधाओं पर निर्भरता के द्वारा प्रदूषित नहीं किया जाना चाहिए, जैसे IDisposableIDisposableउन वर्गों के लिए आरक्षित होना चाहिए जिनका अमूर्त एक संसाधन को घेरता है जो नियतात्मक सफाई के लिए कहता है; यानी, उन कक्षाओं के लिए जहां डिस्पोज़ेबिलिटी एब्सट्रैक्शन का हिस्सा है ।


1
मैं इस बात से पूरी तरह सहमत हूं कि शॉलेस के कार्यान्वयन विवरण को सार्वजनिक इंटरफ़ेस को प्रदूषित नहीं करना चाहिए, लेकिन मेरा कहना है कि इससे बचना मुश्किल हो सकता है। आप यहाँ जो सुझाव देते हैं वह हमेशा संभव नहीं होगा: थ्रेड के बीच संवाद करने के लिए AutoResetEvent () का उद्देश्य है, इसलिए इसका दायरा आमतौर पर एकल विधि से आगे बढ़ेगा।
ग्राहम

@ ग्राहम: इसलिए मैंने इसे इस तरह से डिजाइन करने की कोशिश की। आप डिस्पोजेबल को अन्य तरीकों से भी पास कर सकते हैं। यह केवल तब टूट जाता है जब क्लास के लिए बाहरी कॉल डिस्पोजेबल के जीवनचक्र को नियंत्रित करते हैं। मैं उसी हिसाब से जवाब अपडेट करूंगा।
जोर्डो

2
क्षमा करें, मुझे पता है कि आप डिस्पोजेबल को पास कर सकते हैं, लेकिन मैं अभी भी उस काम को नहीं देख रहा हूं। मेरे उदाहरण में AutoResetEventविभिन्न थ्रेड्स के बीच संवाद करने के लिए उपयोग किया जाता है जो एक ही वर्ग के भीतर काम करते हैं, इसलिए इसे एक सदस्य चर होना चाहिए। आप इसके दायरे को एक विधि तक सीमित नहीं कर सकते। (उदाहरण के लिए कल्पना कीजिए कि एक धागा बस को अवरुद्ध करके किसी काम के लिए इंतजार कर रहा है waitHandle.WaitOne()। मुख्य धागा तब shoelace.Tie()विधि को कॉल करता है, जो सिर्फ एक करता है waitHandle.Set()और सीधे वापस लौटता है)।
ग्राहम

3

यह मूल रूप से तब होता है जब आप कम्पोज़िटिव या एग्रीगेशन को डिस्पोजेबल कक्षाओं के साथ मिलाते हैं। जैसा कि उल्लेख किया गया है, पहला रास्ता वेटहैंडल को फावड़े से बाहर निकालना होगा।

जब आपने मानवरहित संसाधनों को नहीं रखा है, तो आप डिस्पोजेबल पैटर्न को काफी कम कर सकते हैं। (मैं अभी भी इसके लिए एक आधिकारिक संदर्भ की तलाश कर रहा हूं।)

लेकिन आप विध्वंसक और GC.SuppressFinalize (यह) को छोड़ सकते हैं; और शायद वर्चुअल शून्य डिस्पोज़ (बूल डिस्पोज़िंग) को थोड़ा साफ करें।


धन्यवाद हेनक। अगर मैंने वेटहैंडल के निर्माण को शॉलेस से बाहर कर दिया, तो किसी को अभी भी कहीं न कहीं इसका निपटान करना है ताकि किसी को कैसे पता चले कि शॉलेस इसके साथ समाप्त हो गया है (और यह कि शॉलेस ने इसे किसी अन्य कक्षाओं में पास नहीं किया है)?
ग्राहम

आपको न केवल क्रिएशन को स्थानांतरित करने की आवश्यकता होगी, बल्कि वेटहैंडल के लिए 'जिम्मेदारी' भी होगी। jaredPar के उत्तर में एक विचार की दिलचस्प शुरुआत है।
हेंक होल्टरमैन

इस ब्लॉग में आईडीसोफ़रेबल लागू करने को शामिल किया गया है, और विशेष रूप से पते में कि कैसे एक ही वर्ग के ब्लॉग
PaulS

3

दिलचस्प है कि अगर Driverऊपर के रूप में परिभाषित किया गया है:

class Driver
{
    Shoe[] shoes = { new Shoe(), new Shoe() };
}

फिर जब Shoeबनाया जाता है IDisposable, तो FxCop (v1.36) शिकायत नहीं करता है जो Driverभी होना चाहिए IDisposable

हालाँकि अगर इसे इस तरह परिभाषित किया जाता है:

class Driver
{
    Shoe leftShoe = new Shoe();
    Shoe rightShoe = new Shoe();
}

फिर यह शिकायत करेगा।

मुझे संदेह है कि यह केवल एफएक्सकोप की एक सीमा है, बजाय एक समाधान के, क्योंकि पहले संस्करण में Shoeअभी भी उदाहरण बन रहे हैं Driverऔर अभी भी किसी तरह से निपटाने की आवश्यकता है।


2
यदि शो आईडीडायरेक्टली लागू होता है, तो इसे एक फील्ड इनिशियलाइज़र में बनाना खतरनाक है। दिलचस्प है कि FXCop इस तरह के इनिशियलाइज़ेशन की अनुमति नहीं देगा, क्योंकि C # में उन्हें सुरक्षित रूप से करने का एकमात्र तरीका थ्रेडस्टैटिक वैरिएबल (सर्वथा छुपा हुआ) है। Vb.net में, यह संभव है कि थ्रेडिस्टिक वैरिएबल्स के बिना सुरक्षित रूप से आईडीआईसोपायोटिक ऑब्जेक्ट्स को इनिशियलाइज़ किया जाए। कोड अभी भी बदसूरत है, लेकिन इतना छिपा नहीं है। काश एमएस ऐसे फील्ड इनिशियलाइजर्स को सुरक्षित तरीके से इस्तेमाल करने का अच्छा तरीका प्रदान करता।
सुपरकैट

1
@ सुपरकैट: धन्यवाद। क्या आप बता सकते हैं कि यह खतरनाक क्यों है? मैं अनुमान लगा रहा हूं कि अगर एक भी Shoeनिर्माण में एक अपवाद को फेंक दिया गया तो shoesएक मुश्किल स्थिति में छोड़ दिया जाएगा?
ग्राहम

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

3
एकमात्र तरीका जो मुझे पता है कि सी # में उससे निपटने के लिए थ्रेडस्टैटिक चर का उपयोग उन वस्तुओं की एक सूची को रखने के लिए किया जाएगा जो कि वर्तमान कंस्ट्रक्टर फेंकता है, जिसके निपटान की आवश्यकता होगी। फिर प्रत्येक फ़ील्ड इनिशियलाइज़र को प्रत्येक ऑब्जेक्ट के रूप में पंजीकृत किया जाता है, जैसा कि इसे बनाया गया है, कारखाने को सूची को साफ कर देता है यदि यह सफलतापूर्वक पूरा हो जाता है, और सूची से सभी आइटमों को हटाने के लिए "अंत में" खंड का उपयोग करें यदि यह साफ नहीं किया गया था। यह एक व्यावहारिक दृष्टिकोण होगा, लेकिन थ्रेडस्टैटिक चर बदसूरत हैं। Vb.net में, कोई भी किसी भी थ्रेडस्टैटिक चर की आवश्यकता के बिना एक समान तकनीक का उपयोग कर सकता है।
सुपरकैट

3

मुझे नहीं लगता कि अगर आप अपने डिजाइन को इतनी मजबूती से बनाए रखते हैं तो आईडीआईसोपी को फैलने से रोकने का एक तकनीकी तरीका है। यदि डिजाइन सही है तो किसी को आश्चर्य होना चाहिए।

आपके उदाहरण में, मुझे लगता है कि यह जूते के खुद के जूते के होने का मतलब है, और शायद, चालक को अपने जूते खुद चाहिए। हालांकि, बस में ड्राइवर नहीं होना चाहिए। आमतौर पर, बस चालक स्क्रैप के लिए बसों का पालन नहीं करते हैं :) ड्राइवरों और जूतों के मामले में, चालक शायद ही कभी अपने जूते बनाते हैं, जिसका अर्थ है कि वे वास्तव में उन्हें "खुद" नहीं करते हैं।

एक वैकल्पिक डिजाइन हो सकता है:

class Bus
{
   IDriver busDriver = null;
   public void SetDriver(IDriver d) { busDriver = d; }
}

class Driver : IDriver
{
   IShoePair shoes = null;
   public void PutShoesOn(IShoePair p) { shoes = p; }
}

class ShoePairWithDisposableLaces : IShoePair, IDisposable
{
   Shoelace lace = new Shoelace();
}

class Shoelace : IDisposable
{
   ...
}

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


2
यह वास्तव में मूल समस्या का समाधान नहीं करता है। यह FxCop को शांत रख सकता है, लेकिन कुछ को अभी भी Shoelace को निपटाना चाहिए।
एंड्रयूज

मुझे लगता है कि आपने जो भी किया है, वह समस्या कहीं और है। शूपेयरविथडिसोप्रोजेक्टलेस अब शॉलेस () का मालिक है, इसलिए इसे भी आइडीसोपयोगी बनाया जाना चाहिए - ताकि जूते का निपटान कौन करे? क्या आप इसे संभालने के लिए कुछ IoC कंटेनर में छोड़ रहे हैं?
ग्राहम

@AndrewS: वास्तव में, कुछ को अभी भी ड्राइवरों, जूते और लेस का निपटान करना चाहिए, लेकिन बसों द्वारा निपटान शुरू नहीं किया जाना चाहिए। @ ग्राहम: आप सही कह रहे हैं, मैं समस्या को कहीं और ले जा रहा हूं, क्योंकि मेरा मानना ​​है कि यह अन्यत्र है। आमतौर पर, एक क्लास इंस्टेंटिंग जूते होंगे, जो जूते के निपटान के लिए भी जिम्मेदार होंगे। मैंने शूपीयरविथडिसपोजिटरी लेस को डिस्पोजेबल बनाने के लिए कोड को एडिट किया है।
जोह

@ जो: धन्यवाद। जैसा कि आप कहते हैं, इसे कहीं और स्थानांतरित करने का मुद्दा यह है कि आप एक पूरी बहुत अधिक जटिलता पैदा करते हैं। यदि किसी अन्य वर्ग द्वारा जूतापेयरविथडिसपोजेबल लेस बनाया गया है, तो उस वर्ग को तब सूचित नहीं किया जाएगा जब चालक ने अपने जूते के साथ समाप्त कर दिया है, ताकि यह ठीक से उन्हें डिस्पोज़ () कर सके?
ग्राहम

1
@ ग्राहम: हाँ, कुछ प्रकार के एक अधिसूचना तंत्र की आवश्यकता होगी। उदाहरण के लिए, संदर्भ गणना पर आधारित एक निपटान नीति का उपयोग किया जा सकता है। वहाँ कुछ जोड़ा जटिलता है, लेकिन जैसा कि आप शायद जानते हैं, "एक मुफ्त जूते के रूप में ऐसी कोई बात नहीं है" :)
जोह

1

नियंत्रण के व्युत्क्रम का उपयोग कैसे करें?

class Bus
{
    private Driver busDriver;

    public Bus(Driver busDriver)
    {
        this.busDriver = busDriver;
    }
}

class Driver
{
    private Shoe[] shoes;

    public Driver(Shoe[] shoes)
    {
        this.shoes = shoes;
    }
}

class Shoe
{
    private Shoelace lace;

    public Shoe(Shoelace lace)
    {
        this.lace = lace;
    }
}

class Shoelace
{
    bool tied;
    private AutoResetEvent waitHandle;

    public Shoelace(bool tied, AutoResetEvent waitHandle)
    {
        this.tied = tied;
        this.waitHandle = waitHandle;
    }
}

class Program
{
    static void Main(string[] args)
    {
        using (var leftShoeWaitHandle = new AutoResetEvent(false))
        using (var rightShoeWaitHandle = new AutoResetEvent(false))
        {
            var bus = new Bus(new Driver(new[] {new Shoe(new Shoelace(false, leftShoeWaitHandle)),new Shoe(new Shoelace(false, rightShoeWaitHandle))}));
        }
    }
}

अब आप इसे कॉल करने वालों की समस्या बना चुके हैं, और शॉलेस इसकी आवश्यकता होने पर उपलब्ध होने वाले प्रतीक्षा हैंडल पर निर्भर नहीं हो सकता है।
एंडी

@ कैंडी आपका क्या मतलब है "शॉलेस इंतजार के हैंडल पर उपलब्ध नहीं हो सकता है जब उसे इसकी आवश्यकता हो"? इसे कंस्ट्रक्टर को पास कर दिया गया है।
दरगाह

शॉलेस को देने से पहले ऑटोरेसेटेव्स राज्य के साथ कुछ और गड़बड़ हो सकती है, और यह खराब स्थिति में हो सकती है; कुछ और हो सकता है कि राज्य के साथ शेकेल अपनी बात कर रहा हो, जिससे शॉलेस गलत काम करे। इसका एक ही कारण है कि आप केवल निजी सदस्यों पर ताला लगाते हैं। "सामान्य तौर पर, .. अपने कोड नियंत्रण से परे इंस्टेंस पर लॉक करने से बचें" docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
एंडी

मैं केवल निजी सदस्यों पर ताला लगाने से सहमत हूं। लेकिन ऐसा लगता है कि वेट हैंडल अलग हैं। वास्तव में, उन्हें वस्तु में पास करना अधिक उपयोगी लगता है क्योंकि उसी सूत्र का उपयोग थ्रेड्स में संचार करने के लिए किया जाना चाहिए। बहरहाल, मुझे लगता है कि IoC ओपी की समस्या का एक उपयोगी समाधान प्रदान करता है।
दरगाह

यह देखते हुए कि ओपी उदाहरण में एक निजी सदस्य के रूप में वेटहैंडल था, सुरक्षित धारणा यह है कि वस्तु को इसके लिए विशेष पहुंच की उम्मीद है। उदाहरण के बाहर हैंडल को दिखाई देने से उल्लंघन होता है। आमतौर पर एक IoC इस तरह की चीजों के लिए अच्छा हो सकता है, लेकिन जब यह थ्रेडिंग की बात आती है।
एंडी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.