क्या अपवाद सुरक्षा के लिए "स्कोप्ड व्यवहार" प्राप्त करने के लिए एक साधन के रूप में आईडीसोफिल और "का उपयोग करना" अपमानजनक है?


112

C ++ में मैंने जो कुछ भी अक्सर उपयोग किया था वह एक वर्ग को निर्माण और विध्वंसक के माध्यम से Aएक अन्य वर्ग के लिए एक राज्य की प्रविष्टि और निकास की स्थिति को संभालने दे रहा था , यह सुनिश्चित करने के लिए कि यदि उस दायरे में किसी चीज ने अपवाद को फेंक दिया, तो बी को एक ज्ञात स्थिति होगी। दायरे से बाहर किया गया था। यह शुद्ध RAII नहीं है, जहाँ तक यह संक्षिप्त है, लेकिन फिर भी यह एक स्थापित पैटर्न है।BA

C # में, मैं अक्सर करना चाहता हूं

class FrobbleManager
{
    ...

    private void FiddleTheFrobble()
    {
        this.Frobble.Unlock();
        Foo();                  // Can throw
        this.Frobble.Fiddle();  // Can throw
        Bar();                  // Can throw
        this.Frobble.Lock();
    }
}

जिसे इस तरह से करने की जरूरत है

private void FiddleTheFrobble()
{
    this.Frobble.Unlock();

    try
    {            
        Foo();                  // Can throw
        this.Frobble.Fiddle();  // Can throw
        Bar();                  // Can throw
    }
    finally
    {
        this.Frobble.Lock();
    }
}

अगर मैं Frobbleराज्य की गारंटी देना चाहता हूं, जब FiddleTheFrobbleरिटर्न देता है। कोड के साथ अच्छा होगा

private void FiddleTheFrobble()
{
    using (var janitor = new FrobbleJanitor(this.Frobble))
    {            
        Foo();                  // Can throw
        this.Frobble.Fiddle();  // Can throw
        Bar();                  // Can throw
    }
}

जहां लगभग जैसा FrobbleJanitorदिखता है

class FrobbleJanitor : IDisposable
{
    private Frobble frobble;

    public FrobbleJanitor(Frobble frobble)
    {
        this.frobble = frobble;
        this.frobble.Unlock();
    }

    public void Dispose()
    {
        this.frobble.Lock();
    }
}

और यही मैं इसे करना चाहता हूं। अब वास्तविकता, पकड़ता है के बाद से मैं क्या चाहते हैं उपयोग करने के लिए की आवश्यकता है कि FrobbleJanitorप्रयोग किया जाता है के साथ using । मैं इसे एक कोड समीक्षा मुद्दे पर विचार कर सकता था, लेकिन कुछ मुझे परेशान कर रहा है।

प्रश्न: क्या उपरोक्त को अपमानजनक माना जाएगा usingऔर IDisposable?


23
कक्षा के लिए +1 और नाम अकेले :-)। ठीक है, निष्पक्ष और वास्तविक सवाल है।
जॉय

2
@ जोहान्स: हाँ, मैं देख सकता हूँ कि क्यों - ज्यादातर लोग सिर्फ अपनी बेईमानी को रोकते हैं, लेकिन मुझे इसका विरोध करना चाहिए। ;-) और, आपके नाम समानता के लिए +1।
जोहान जेरेल

शायद आप इस उदाहरण में एक ही परिणाम प्राप्त करने के लिए लॉक (इस) {..} गुंजाइश का उपयोग कर सकते हैं?
o

1
@ o @: आप विभिन्न थ्रेड्स से किसी चीज़ तक एक साथ पहुँच को रोकने के लिए लॉक () का उपयोग करते हैं। मेरे द्वारा वर्णित परिदृश्य से कोई लेना देना नहीं है।
जोहान जेरेल

1
सी # :) के अगले संस्करण में कोई फ़ाइनलीज़र के साथ उपलब्ध नहीं है
जॉन

जवाबों:


33

मुझे ऐसा नहीं लगता, जरूरी है। तकनीकी रूप से उपयोग करने का मतलब गैर-प्रबंधित संसाधनों वाली चीजों के लिए इस्तेमाल किया जाना है, लेकिन तब निर्देश का उपयोग आम पैटर्न को लागू करने का सिर्फ एक अच्छा तरीका है try .. finally { dispose }

एक शुद्धतावादी तर्क देगा 'हाँ - यह अपमानजनक है', और शुद्ध अर्थ में यह है; लेकिन हम में से अधिकांश एक शुद्धतावादी दृष्टिकोण से नहीं, बल्कि एक अर्ध-कलात्मक से कोड करते हैं। इस तरह से 'उपयोग' निर्माण का उपयोग करना वास्तव में काफी कलात्मक है, मेरी राय में।

आपको शायद अन्य इंटरफ़ेस के बारे में बताने के लिए अन्य इंटरफ़ेस के बारे में बताने के लिए IDis प्रयोज्य के शीर्ष पर एक और इंटरफ़ेस चिपकाना चाहिए, जिससे अन्य इंटरफ़ेस IDO प्रयोज्य का पता लगा सके।

ऐसा करने के लिए बहुत सारे अन्य विकल्प हैं लेकिन, आखिरकार, मैं किसी के बारे में सोच भी नहीं सकता जो इस तरह से साफ-सुथरा होगा, इसलिए इसके लिए जाएं!


2
मेरा मानना ​​है कि यह "उपयोग" के साथ-साथ एक कलात्मक उपयोग भी है। मुझे लगता है कि एरिक गुनरसन की एक टिप्पणी से जोड़ने वाला सैम्युल जैक का पोस्ट "उपयोग" के इस कार्यान्वयन को मान्य करता है। मैं इस पर आंद्रेस और एरिक दोनों से बने उत्कृष्ट बिंदु देख सकता हूं।
19

1
मैंने कुछ समय पहले एरिक गुनरसन से इस बारे में बात की थी और उनके अनुसार, यह सी # डिजाइन टीम का इरादा था, जो कि स्कोप्स को दर्शाती है। वास्तव में, उन्होंने पोस्ट किया कि उन्होंने लॉक स्टेटमेंट से पहले डिजाइन किया था, हो सकता है कि लॉक स्टेटमेंट भी न हो। यह एक ब्लॉकिंग डब्ल्यू / एक मॉनिटर कॉल या कुछ और होता। अद्यतन: बस एहसास हुआ कि अगला जवाब एरिक लिपर्ट का है जो भाषाओं की टीम में भी है। ;) शायद सी # टीम खुद इस बारे में पूरी सहमति में नहीं है? मेरी चर्चा w / Gunnerson का संदर्भ TimedLock वर्ग था: bit.ly/lKugIO
Haacked

2
@ हेकड - अम्यूज़िंग यह नहीं है; आपकी टिप्पणी पूरी तरह से मेरी बात साबित करती है; आपने टीम के एक आदमी से बात की थी और वह इसके लिए था; फिर एरिक लिपर्ट को इंगित करते हुए, उसी टीम से असहमत। मेरे नज़रिये से; C # एक ऐसा कीवर्ड प्रदान करता है जो एक इंटरफ़ेस का उपयोग करता है और एक अच्छा दिखने वाला कोड पैटर्न उत्पन्न करने के लिए भी होता है जो इतने सारे परिदृश्यों में काम करता है। यदि हम इसका दुरुपयोग नहीं करते हैं, तो C # को लागू करने का एक और तरीका खोजना चाहिए। किसी भी तरह से, डिजाइनरों को शायद यहां एक पंक्ति में अपने बतख प्राप्त करने की आवश्यकता है! इस बीच: using(Html.BeginForm())सर? बुरा मत मानना ​​अगर मैं सर! :)
एंड्रास ज़ोल्टन

71

मैं इसे उपयोग करने वाले कथन का दुरुपयोग मानता हूं। मुझे पता है कि मैं इस पद पर अल्पमत में हूं।

मैं इसे तीन कारणों से दुरुपयोग मानता हूं।

सबसे पहले, क्योंकि मुझे उम्मीद है कि "उपयोग" का उपयोग एक संसाधन का उपयोग करने के लिए किया जाता है और जब आप इसके साथ काम करते हैं तो इसका निपटान करते हैं । प्रोग्राम की स्थिति बदलना एक संसाधन का उपयोग नहीं कर रहा है और इसे वापस बदलना कुछ भी निपटाना नहीं है। इसलिए, राज्य को बदलने और बहाल करने के लिए "उपयोग" एक दुरुपयोग है; कोड आकस्मिक पाठक के लिए भ्रामक है।

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

और तीसरा, आपके कार्यक्रम की क्रियाएं उसके राज्य द्वारा निर्धारित की जाती हैं; राज्य के सावधानीपूर्वक हेरफेर की आवश्यकता ठीक है क्योंकि हम पहली बार में यह बातचीत कर रहे हैं। आइए विचार करें कि हम आपके मूल कार्यक्रम का विश्लेषण कैसे कर सकते हैं।

क्या आप इसे मेरे कार्यालय में एक कोड की समीक्षा करने के लिए लाएंगे, पहला सवाल जो मैं पूछूंगा "क्या यह अपवाद को फेंकने के लिए वास्तव में फ्रॉबल को लॉक करना सही है?" यह आपके कार्यक्रम से स्पष्ट रूप से स्पष्ट है कि यह चीज़ आक्रामक रूप से फिर से ताला लगा देती है चाहे कुछ भी हो जाए। क्या वह सही है? एक अपवाद फेंक दिया गया है। कार्यक्रम एक अज्ञात स्थिति में है। हम नहीं जानते कि क्या फू, फिडल या बार ने फेंक दिया, क्यों उन्होंने फेंक दिया, या उन्होंने अन्य राज्यों को क्या परिवर्तन किए जो साफ नहीं किए गए थे। क्या आप मुझे समझा सकते हैं कि उस भयानक स्थिति में हमेशा दोबारा ताला लगाना सही काम है?

शायद यह है, शायद यह नहीं है। मेरा कहना यह है कि कोड के साथ जैसा कि मूल रूप से लिखा गया था, कोड समीक्षक प्रश्न पूछना जानता है । उस कोड के साथ जो "उपयोग" करता है, मैं सवाल पूछना नहीं जानता; मुझे लगता है कि "उपयोग" ब्लॉक एक संसाधन आवंटित करता है, इसे थोड़ा उपयोग करता है, और जब यह किया जाता है, तो विनम्रता से इसका निपटान करता है, न कि "उपयोग" ब्लॉक का समापन ब्रेस मेरे प्रोग्राम स्टेट को असाधारण रूप से कई मनमाने ढंग से उत्परिवर्तित करता है कार्यक्रम राज्य की स्थिरता की शर्तों का उल्लंघन किया गया है।

सिमेंटिक प्रभाव के लिए "उपयोग" ब्लॉक का उपयोग इस कार्यक्रम को खंडित करता है:

}

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

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

bool needsLock = false;
try
{
    // must be carefully written so that needsLock is set
    // if and only if the unlock happened:

    this.Frobble.AtomicUnlock(ref needsLock);
    blah blah blah
}
finally
{
    if (needsLock) this.Frobble.Lock();
}

फिर, शायद यह करता है, शायद यह नहीं है, लेकिन मैं सवाल पूछना जानता हूं । "उपयोग" संस्करण के साथ, यह एक ही समस्या के लिए अतिसंवेदनशील है: थ्रोबल बंद होने के बाद एक थ्रेड एबॉर्ट अपवाद को फेंक दिया जा सकता है, लेकिन उपयोग करने से जुड़े प्रयास से संरक्षित क्षेत्र में प्रवेश करने से पहले। लेकिन "उपयोग" संस्करण के साथ, मुझे लगता है कि यह एक "तो क्या है?" परिस्थिति। यदि ऐसा होता है तो यह दुर्भाग्यपूर्ण है, लेकिन मेरा मानना ​​है कि "उपयोग करना" केवल विनम्र होना है, न कि व्यावहारिक रूप से महत्वपूर्ण राज्य को बदलने के लिए। मुझे लगता है कि अगर कुछ भयानक थ्रेड एबॉर्ट अपवाद गलत समय पर होता है, तो ठीक है, कचरा कलेक्टर अंतिम रूप से चलाने से उस संसाधन को साफ कर देगा।


18
हालांकि मैं इस प्रश्न का उत्तर अलग तरह से दूंगा, लेकिन मुझे लगता है कि यह एक अच्छी तरह से तर्कपूर्ण पोस्ट है। हालाँकि, मैं आपके दावे के साथ usingमुद्दा उठाता हूं जो शुद्धता के मुद्दे के बजाय एक राजनीतिकता है। मेरा मानना ​​है कि संसाधन लीक में शुद्धता के मुद्दे हैं, हालांकि अक्सर वे काफी छोटे होते हैं कि वे उच्च प्राथमिकता वाले बग नहीं होते हैं। इस प्रकार, usingब्लॉक पहले से ही कार्यक्रम की स्थिति पर अर्थ प्रभाव डालते हैं, और वे जो रोकते हैं वह अन्य प्रक्रियाओं के लिए "असुविधा" नहीं है, लेकिन संभवतः एक टूटा हुआ वातावरण है। यह कहना नहीं है कि प्रश्न द्वारा निहित विभिन्न प्रकार के अर्थ प्रभाव भी उचित हैं।
kvb

13
संसाधन लीक सही मुद्दे हैं, हाँ। लेकिन "उपयोग" करने में विफलता संसाधन को लीक नहीं करती है; जब फाइनल चलेगा तो संसाधन को अंततः साफ कर दिया जाएगा। क्लीनअप जितना हो सके उतना आक्रामक और समय पर नहीं होगा, लेकिन ऐसा होगा।
एरिक लिपर्ट

7
अद्भुत पोस्ट, यहाँ मेरे दो सेंट :) मुझे बहुत "गाली" पर संदेह usingहै क्योंकि यह एक गरीब आदमी का सी # में उन्मुख बुनकर है। डेवलपर वास्तव में क्या चाहता है यह गारंटी देने का एक तरीका है कि कुछ आम कोड उस कोड को डुप्लिकेट किए बिना एक ब्लॉक के अंत में चलेगा। C # आज AOP का समर्थन नहीं करता है (MarsBBRROOject और PostSharp नहीं समझे)। हालांकि, उपयोग कथन के संकलक का परिवर्तन नियतात्मक संसाधन निपटान के शब्दार्थों को पुन: शुद्ध करके सरल AOP को प्राप्त करना संभव बनाता है। एक अच्छा अभ्यास नहीं है, लेकिन कभी-कभी यह पास करने के लिए आकर्षक होता है .....
LBushkin

11
जब मैं आम तौर पर आपकी स्थिति से सहमत होता हूं, तो कुछ मामले ऐसे होते हैं, जहां पुनर्पूंजीकरण usingका लाभ छोड़ने के लिए बहुत आकर्षक होता है। कोड टाइमिंग को ट्रैक करने और रिपोर्ट करने के लिए मैं सबसे अच्छा उदाहरण सोच सकता हूं: using( TimingTrace.Start("MyMethod") ) { /* code */ } फिर से, यह एओपी है - Start()ब्लॉक शुरू होने से पहले प्रारंभ समय को Dispose()कैप्चर करता है, अंत समय को कैप्चर करता है और गतिविधि को लॉग करता है। यह कार्यक्रम की स्थिति को नहीं बदलता है और अपवादों के लिए अज्ञेयवादी है। यह आकर्षक भी है क्योंकि यह प्लंबिंग से काफी हद तक बचता है और पैटर्न के रूप में अक्सर इसका उपयोग भ्रमित करने वाले शब्दार्थ को कम करता है।
LBushkin

6
मजेदार, मैंने हमेशा RAII के समर्थन के साधन के रूप में उपयोग करने के बारे में सोचा। यह एक संसाधन का एक प्रकार होने के लिए एक ताला पर विचार करने के लिए मुझे उचित रूप से सहज लगता है।
ब्रायन

27

यदि आप कुछ साफ, स्कोप कोड चाहते हैं, तो आप लैम्ब्डा, á la का भी उपयोग कर सकते हैं

myFribble.SafeExecute(() =>
    {
        myFribble.DangerDanger();
        myFribble.LiveOnTheEdge();
    });

जहां .SafeExecute(Action fribbleAction)विधि try- catch- finallyब्लॉक को लपेटता है ।


उस उदाहरण में, आपने प्रविष्टि स्थिति को याद किया। इसके अलावा, सुनिश्चित करें कि आप कोशिश करते हैं / अंत में लपेटते हैं, लेकिन आप अंत में कुछ भी नहीं कहते हैं, इसलिए यदि लैम्ब्डा में कुछ फेंकता है तो आपको पता नहीं है कि आप किस स्थिति में हैं।
जोहान जेरेल

1
आह! ठीक है, मुझे लगता है कि आपका मतलब है कि SafeExecuteएक Fribbleविधि है जो कॉल करती है Unlock()और Lock()लिपटे हुए प्रयास में / आखिरकार। मेरी माफ़ी तब। मैंने तुरंत SafeExecuteएक सामान्य एक्सटेंशन विधि के रूप में देखा और इसलिए प्रवेश और निकास राज्य की कमी का उल्लेख किया। मेरी गलती।
जोहान गेरेल

1
इस apporach के साथ बहुत सावधान रहें। पकड़े गए स्थानीय लोगों के मामले में कुछ खतरनाक सूक्ष्म अनपेक्षित आजीवन एक्सटेंशन हो सकते हैं!
जेसन

4
युक। क्यों छिपाने की कोशिश / पकड़ / अंत में? दूसरों के लिए पढ़ने के लिए अपने कोड को छुपाता है।
फ्रैंक श्वेतेरमैन

2
@ युकी फ्रैंक: यह कुछ भी "छिपाने" का मेरा विचार नहीं था , यह प्रश्नकर्ता का अनुरोध था। :-P ... उस ने कहा, अनुरोध "अपने आप को दोहराएं नहीं" की बात है। आपके पास बहुत सी विधियाँ हो सकती हैं, जिन्हें किसी चीज़ को साफ़ करने / जारी करने के लिए उसी बॉयलरप्लेट के "फ्रेम" की आवश्यकता होती है और आप उसे कॉल करने वाले (एनकैप्सुलेशन के बारे में) को लागू नहीं करना चाहते हैं। इसके अलावा कोई भी नाम जैसे तरीकों का नाम दे सकता है। सुरक्षित रूप से (...) अधिक स्पष्ट रूप से अच्छी तरह से संवाद करने के लिए कि वे क्या करते हैं।
हर्जमेस्टर

25

एरिक गुनरसन, जो C # भाषा डिजाइन टीम में थे, ने इस प्रश्न का बहुत ही समान उत्तर दिया :

डौग पूछता है:

पुन: टाइमआउट के साथ एक लॉक स्टेटमेंट ...

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

डौग,

जब हमने निर्णय लेने के लिए [sic] निर्णय लिया, तो हमने वस्तुओं का निस्तारण करने के लिए कुछ अधिक विशिष्ट के बजाय इसका उपयोग "नाम" करने का निर्णय लिया, ताकि इसका उपयोग इस परिदृश्य के लिए किया जा सके।


4
वैसे उस उद्धरण को कहना चाहिए कि जब वह "वास्तव में इस परिदृश्य" का उल्लेख कर रहा था, तो मुझे संदेह है कि वह इस भविष्य के प्रश्न का उल्लेख कर रहा था।
फ्रैंक श्वेतेरमैन

4
@ फ्रेंक श्वाइटरमैन: मैंने उद्धरण पूरा किया। जाहिर है, सी # टीम की ओर से लोगों को किया था लगता है कि usingसुविधा गया था नहीं संसाधन निपटान करने के लिए सीमित किया जाना है।
पियरसबल

11

यह एक फिसलन ढलान है। आईडीसोपायरी का एक अनुबंध है, एक वह जो फाइनल-अप द्वारा समर्थित है। एक फाइनलर आपके मामले में बेकार है। आप ग्राहक को कथन का उपयोग करने के लिए मजबूर नहीं कर सकते, केवल उसे ऐसा करने के लिए प्रोत्साहित करें। आप इसे इस तरह से एक विधि के साथ मजबूर कर सकते हैं:

void UseMeUnlocked(Action callback) {
  Unlock();
  try {
    callback();
  }
  finally {
    Lock();
  }
}

लेकिन वह लमदा के बिना थोड़ा अजीब हो जाता है। उस ने कहा, जैसे मैंने किया था, मैंने आईडीसॉपी का उपयोग किया है।

हालांकि आपके पोस्ट में एक विवरण है जो इसे खतरनाक रूप से एक विरोधी पैटर्न के करीब बनाता है। आपने उल्लेख किया कि वे विधियाँ अपवाद को फेंक सकती हैं। यह ऐसा कुछ नहीं है जिसे कॉलर अनदेखा कर सकता है। वह उस बारे में तीन काम कर सकता है:

  • कुछ भी न करें, अपवाद पुनर्प्राप्त करने योग्य नहीं है। सामान्य मामला है। अनलॉक कॉल करना कोई मायने नहीं रखता।
  • अपवाद को पकड़ो और संभालो
  • अपने कोड में राज्य को पुनर्स्थापित करें और अपवाद को कॉल श्रृंखला से गुजरने दें।

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


जबरन मामला "हर्जमेस्टर डेर वेल्टेन" द्वारा ऊपर दिया गया था, मुझे लगता है - भले ही ओपी को उदाहरण पसंद नहीं आया।
बेंजामिन पॉडज़ुन

हां, मैंने उसकी व्याख्या SafeExecuteएक सामान्य विस्तार विधि के रूप में की। अब मैं देख रहा हूं कि यह एक Fribbleविधि के रूप में होने की संभावना थी जो कॉल करती है Unlock()और Lock()लिपटे हुए प्रयास / अंत में। मेरी गलती।
जोहान जेरेल

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

7

एक वास्तविक दुनिया का उदाहरण ASP.net MVC की शुरुआत है। मूल रूप से आप लिख सकते हैं:

Html.BeginForm(...);
Html.TextBox(...);
Html.EndForm();

या

using(Html.BeginForm(...)){
    Html.TextBox(...);
}

Html.EndForm कॉल डिस्पोज़, और डिस्पोज़ सिर्फ आउटपुट </form> टैग को । इसके बारे में अच्छी बात यह है कि {} कोष्ठक एक दृश्यमान "स्कोप" बनाते हैं जिससे यह देखना आसान हो जाता है कि फॉर्म के भीतर क्या है और क्या नहीं।

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

व्यक्तिगत रूप से मैं इसका उपयोग केवल तभी करूंगा जब निम्नलिखित दो नियम सही होंगे, लेकिन मेरे द्वारा मनमाने ढंग से सेट किए गए हैं:

  • निपटान एक ऐसा कार्य होना चाहिए जो हमेशा चलता रहे, इसलिए नल-चेक को छोड़कर कोई भी स्थिति नहीं होनी चाहिए
  • डिस्पोज़ () के बाद, ऑब्जेक्ट फिर से उपयोग करने योग्य नहीं होना चाहिए। अगर मुझे एक पुन: प्रयोज्य वस्तु चाहिए थी, तो मैं इसे डिस्पोज़ करने के बजाय इसे खुले / करीब तरीके देना चाहता हूं। इसलिए मैं एक InvalidOperationException को फेंक देता हूं जब एक डिस्पोजल ऑब्जेक्ट का उपयोग करने की कोशिश करता हूं।

अंत में, यह सब उम्मीदों के बारे में है। यदि कोई वस्तु आईडीसोपायरी को लागू करती है, तो मुझे लगता है कि उसे कुछ सफाई करने की आवश्यकता है, इसलिए मैं इसे कॉल करता हूं। मुझे लगता है कि यह आमतौर पर "शटडाउन" फ़ंक्शन होता है।

कहा जा रहा है, मुझे यह लाइन पसंद नहीं है:

this.Frobble.Fiddle();

FrobbleJanitor के रूप में "Frobble का मालिक अब" है, मुझे आश्चर्य है कि क्या इसके बजाय बेहतर होगा कि वह Frobble को Janitor में न कहे?


आपके "मुझे यह पंक्ति पसंद नहीं है" के बारे में - मैंने वास्तव में संक्षिप्त रूप में प्रश्न को तैयार करते समय इसे करने के बारे में सोचा था, लेकिन मैं अपने प्रश्न के शब्दार्थ को अव्यवस्थित नहीं करना चाहता था। लेकिन मैं आपसे सहमत हूं। एक प्रकार का। :)
जोहान जेरेल

1
Microsoft से स्वयं एक उदाहरण प्रदान करने के लिए बनाया गया। ध्यान दें कि आपके द्वारा उल्लिखित मामले में फेंका जाने वाला एक विशिष्ट अपवाद है: ObjectDisposedException।
एंटीटून

4

हमारे कोड बेस में इस पैटर्न का बहुत उपयोग होता है, और मैंने इसे पहले भी पूरी जगह पर देखा है - मुझे यकीन है कि इसकी चर्चा यहाँ भी हुई होगी। सामान्य तौर पर मैं नहीं देखता कि ऐसा करने में क्या गलत है, यह एक उपयोगी पैटर्न प्रदान करता है और कोई वास्तविक नुकसान नहीं पहुंचाता है।


4

इस पर चिंतन करना: मैं यहां सबसे सहमत हूं कि यह नाजुक है, लेकिन उपयोगी है। मैं आपको System.Transaction.TransactionScope वर्ग की ओर इंगित करना चाहता हूं , जो कुछ ऐसा करना चाहता है जो आप करना चाहते हैं।

आमतौर पर मुझे वाक्य रचना पसंद है, यह असली मांस से बहुत अधिक अव्यवस्था को हटाता है। कृपया सहायक वर्ग को एक अच्छा नाम देने पर विचार करें - हो सकता है ... शायद, ऊपर दिए गए उदाहरण की तरह। नाम को छोड़ देना चाहिए कि यह कोड का एक टुकड़ा encapsulate करता है। * स्कोप, * ब्लॉक या कुछ इसी तरह करना चाहिए।


1
स्कोपगार्ड ने लोकी को अपना रास्ता बनाने से पहले "जेनिटर" आंद्रेई अलेक्जेंड्रेस्कू के एक पुराने सी ++ लेख से स्कोपगार्ड के बारे में बताया।
जोहान गेरेल

@ बैंजामिन: मुझे ट्रांजैक्शनस्कोप क्लास पसंद है, इसके बारे में पहले नहीं सुना था। हो सकता है कि क्योंकि मैं .net CF भूमि में हूँ, जहाँ यह शामिल नहीं है ...
:(

4

नोट: मेरा दृष्टिकोण संभवतः मेरी C ++ पृष्ठभूमि से पक्षपाती है, इसलिए मेरे उत्तर के मूल्य का उस संभावित पूर्वाग्रह के खिलाफ मूल्यांकन किया जाना चाहिए ...

C # भाषा विशिष्टता क्या है?

उद्धरण # भाषा विशिष्टता :

8.13 कथन का उपयोग करना

[...]

एक संसाधन एक वर्ग या संरचना है जो System.IDisposable को लागू करता है, जिसमें एक एकल पैरामीटरलेस विधि शामिल है जिसका नाम निपटान है। एक संसाधन का उपयोग करने वाला कोड यह बताने के लिए Dispose को कॉल कर सकता है कि संसाधन की अब आवश्यकता नहीं है। यदि डिस्पोज़ को नहीं कहा जाता है, तो अंततः कचरा निपटान के परिणामस्वरूप स्वत: निपटान होता है।

कोड है कि एक संसाधन उपयोग कर रहा है , ज़ाहिर है, कोड से शुरू कर रहा है usingकीवर्ड और गुंजाइश से जुड़ी जब तक जा रहा using

तो मुझे लगता है कि यह ठीक है क्योंकि ताला एक संसाधन है।

शायद कीवर्ड usingबुरी तरह से चुना गया था। शायद इसे बुलाया जाना चाहिए था scoped

फिर, हम लगभग कुछ भी संसाधन के रूप में विचार कर सकते हैं। एक फ़ाइल संभाल। एक नेटवर्क कनेक्शन ... एक धागा?

एक धागा???

usingकीवर्ड का उपयोग करना (या दुरुपयोग करना) ?

क्या यह (एब) इस दायरे से बाहर निकलने से पहले थ्रेड के काम को समाप्त करने के लिए कीवर्ड का उपयोग करने के लिए चमकदार होगा using?

हर्ब सटर को लगता है कि यह चमकदार है , क्योंकि वह एक सूत्र के काम करने के लिए इंतजार करने के लिए IDispose पैटर्न का एक दिलचस्प उपयोग प्रस्तुत करता है:

http://www.drdobbs.com/go-parallel/article/showArticle.jhtml?articleID=225700095

यहाँ लेख से कॉपी-पेस्ट किया गया है:

// C# example
using( Active a = new Active() ) {    // creates private thread
       
       a.SomeWork();                  // enqueues work
       
       a.MoreWork();                   // enqueues work
       
} // waits for work to complete and joins with private thread

जबकि सक्रिय ऑब्जेक्ट के लिए C # कोड प्रदान नहीं किया गया है, यह लिखा है C # कोड के लिए आईडी पैटर्न का उपयोग करता है जिसका C ++ संस्करण विनाशकारी में निहित है। और सी ++ संस्करण को देखकर, हम एक विनाशकारी को देखते हैं जो बाहर निकलने से पहले आंतरिक धागे की प्रतीक्षा करता है, जैसा कि लेख के इस अन्य उद्धरण में दिखाया गया है:

~Active() {
    // etc.
    thd->join();
 }

इसलिए, जहाँ तक हर्ब का सवाल है, यह चमकदार है


3

मेरा मानना ​​है कि आपके प्रश्न का उत्तर नहीं है, यह दुरुपयोग नहीं होगा IDisposable

जिस तरह से मैं IDisposableइंटरफ़ेस को समझ रहा हूं वह यह है कि आप एक वस्तु के साथ काम करने वाले नहीं हैं क्योंकि इसे निपटाया गया है (इसके अलावा आपको इसकी Disposeविधि को जितनी बार चाहें कॉल करने की अनुमति है )।

चूँकि आप स्टेटमेंट में हर बार एक नया FrobbleJanitor स्पष्ट रूप से बनाते हैं using, आप कभी भी एक ही FrobbeJanitorवस्तु का दो बार उपयोग नहीं करते हैं । और चूंकि इसका उद्देश्य किसी अन्य वस्तु का प्रबंधन करना है, इसलिए इसे Dispose("प्रबंधित") संसाधन को मुक्त करने के कार्य के लिए उपयुक्त लगता है।

(Btw।, मानक नमूना कोड Disposeलगभग हमेशा उचित कार्यान्वयन का प्रदर्शन बताता है कि प्रबंधित संसाधनों को मुक्त किया जाना चाहिए, न कि केवल अप्रबंधित संसाधन जैसे कि फ़ाइल सिस्टम हैंडल।)

केवल एक चीज मैं कहाँ था व्यक्तिगत रूप से चिंता यह कम स्पष्ट है कि क्या के साथ हो रहा है है using (var janitor = new FrobbleJanitor())एक और अधिक स्पष्ट के साथ की तुलना में try..finallyब्लॉक जहां Lockऔर Unlockसंचालन सीधे दिखाई दे रहे हैं। लेकिन जो दृष्टिकोण लिया जाता है वह शायद व्यक्तिगत प्राथमिकताओं के मामले में आता है।


1

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


1

मुझे लगता है आपने सही किया। ओवरलोडिंग डिस्पोज़ () एक समस्या होगी जो उसी वर्ग ने बाद में सफाई की थी जो वास्तव में उसे करना था, और उस सफाई का जीवनकाल तब अलग हो गया जब आप लॉक रखने की उम्मीद करते हैं। लेकिन जब से आपने एक अलग वर्ग (FrobbleJanitor) बनाया है जो केवल Frobble को लॉक करने और अनलॉक करने के लिए जिम्मेदार है, चीजें पर्याप्त रूप से डिकॉउन्ड की जाती हैं, तो आप उस मुद्दे को हिट नहीं करेंगे।

मैं FrobbleJanitor का नाम बदलूंगा, शायद FrobbleLockSession जैसी किसी चीज के लिए।


नाम बदलने के बारे में - मैंने लॉक / अनलॉक के साथ प्राथमिक कारण के "Janitor" का उपयोग किया। मैंने सोचा कि यह अन्य नाम विकल्पों के साथ गाया जाता है। ;-) अगर मैं अपने कोड बेस में एक पैटर्न के रूप में इस पद्धति का उपयोग करने के लिए था, तो मैं निश्चित रूप से कुछ और उदार वर्णनात्मक शामिल करूंगा, जैसा कि आपने "सत्र" के साथ निहित किया है। यदि यह पुराने C ++ दिन रहा होता, तो मैं शायद FrobbleUnlockScope का उपयोग करता।
जोहान जेरेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.