एक विधि क्यों है जो एक बूल / इंट लौटाती है और वास्तविक वस्तु आउटपुट आउटपुट के रूप में है?


12

मुझे अपनी कंपनी के कोडबेस (.NET 3.5 एप्लीकेशन) में निम्नलिखित कोड पैटर्न सभी जगह दिखाई देते हैं:

bool Foo(int barID, out Baz bazObject) { 
    try { 
            // do stuff
            bazObject = someResponseObject;

            return true;
    }
    catch (Exception ex) { 
        // log error
        return false;
    }
}

// calling code
BazObject baz = new BazObject();
fooObject.Foo(barID, out baz);

if (baz != null) { 
    // do stuff with baz
}

मैं अपने सिर को चारों ओर लपेटने की कोशिश कर रहा हूं कि ऐसा करने के बजाय आप ऐसा क्यों करेंगे क्योंकि Fooविधि केवल आईडी लेती है और एक Bazवस्तु लौटाती है, इसके बजाय एक मूल्य वापस नहीं किया जाता है जिसका उपयोग नहीं किया जाता है और वास्तविक वस्तु एक रेफ या आउटपुट पैरामीटर होता है।

क्या इस कोडिंग शैली का कुछ छिपा हुआ लाभ है जो मुझे याद आ रहा है?



अपने उदाहरण में, bazकिया जा रहा है nullऔर वापस आ boolजा रहा है falseकर रहे हैं नहीं के बराबर। new BazObject()ऐसा कभी नहीं होता है null, इसलिए जब तक bazObjectइसे Exceptionफेंका नहीं जाता है Foo, जब falseलौटाया जाता है , तब तक इसे अपडेट bazनहीं किया जाएगा null। यह काफी मदद मिलेगी अगर कल्पना के लिए Fooउपलब्ध थे। वास्तव में, यह इस कोड द्वारा प्रदर्शित सबसे गंभीर समस्या है।
स्टीव पॉवेल

मेरी स्मृति धुंधली है क्योंकि यह बहुत समय पहले था लेकिन मुझे लगता है कि मैंने उदाहरण गड़बड़ कर दिया था और यह जाँच रहा था कि क्या "बाज" झूठा था, यदि यह अशक्त नहीं था। किसी भी घटना में पैटर्न मुझे वास्तव में पुरातन लगता था, जैसे कि यह VB6 से था और डेवलपर ने कभी भी अपने कोड में सुधार करने की जहमत नहीं उठाई (जो उसने नहीं की)
वेन मोलिना

जवाबों:


11

आप आमतौर पर उस पैटर्न का उपयोग करते हैं ताकि आप इस तरह कोड लिख सकें:

if (Foo(barId, out bazObject))
{
  //DoStuff with bazobject
}

उदाहरण के लिए डिक्शनरी क्लास में TryGetValue के लिए CLR में इसका उपयोग किया जाता है। यह कुछ अतिरेक से बचा जाता है, लेकिन बाहर और रेफरी पैरामीटर मुझे हमेशा थोड़ा गड़बड़ लगता है


1
+1, यही कारण है कि, हालांकि मैं बूलियन और वस्तु दोनों को अलग
pdr

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

यह उत्तर इस पैटर्न के उपयोग को सही ठहराता है। लेकिन अगर यह सब आपके कोडबेस है, तो शायद यह सीन की तरह एक बुरा अभ्यास है।
कोडिज्म

11

यह पुराना C स्टाइल कोड है, इससे पहले अपवाद थे। वापसी मूल्य ने संकेत दिया कि विधि सफल थी या नहीं, और यदि यह था, तो पैरामीटर परिणाम से भरा होगा।

इननेट में हमारे पास उस उद्देश्य के लिए अपवाद हैं। इस पैटर्न का पालन करने का कोई कारण नहीं होना चाहिए।

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


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

ऐसा मैंने नहीं कहा। यदि आप उस कोड को पढ़ते हैं जिसे ओपी ने पोस्ट किया है, तो स्पष्ट रूप से एक अपवाद मामला हो रहा है, लेकिन विधि इसे पकड़ लेती है और बदले में झूठी लौट आती है। यह प्रश्न त्रुटि से संबंधित है, अपेक्षित परिस्थितियों से नहीं।
शॉन एडवर्ड्स

हाँ, यह मुख्य रूप से उन तरीकों में उपयोग किया जाता है जो डेटाबेस से डेटा लोड करते हैं जैसे कि if (baz.Select())लेकिन अधिक बार वापसी मूल्य से अधिक नहीं बस फेंक दिया जाता है और मान को शून्य या कुछ संपत्ति के खिलाफ जांचा जाता है।
वेन मोलिना

@ सीन, देखें कि आप क्या कह रहे हैं, मैं सिर्फ वाक्यांश के लिए आपत्ति करता हूं ".NET में हमारे पास उस उद्देश्य के लिए अपवाद हैं।" अपवाद मेरे लिए एक पूरी तरह से अलग उद्देश्य की सेवा करते हैं
पीडीआर

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

2

कोड स्निपेट को देखते हुए यह पूरी तरह से व्यर्थ दिखता है। मेरे लिए प्रारंभिक कोड पैटर्न सुझाव देगा कि BazObject के लिए अशक्त एक स्वीकार्य मामला होगा और बूल वापसी सुरक्षित रूप से एक असफल मामले को निर्धारित करने का एक उपाय है। यदि निम्न कोड था:

// calling code
BazObject baz = new BazObject();
bool result = fooObject.Foo(barID, out baz);

if (result) { 
    // do stuff with baz
    // where baz may be 
    // null without a 
    // thrown exception
}

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


मुझे लगता है कि यह टीम के एक मौजूदा सदस्य द्वारा लिखा गया था। शायद यही कुछ मुझे O_O के बारे में चिंता करना चाहिए
वेन मोलिना

@Wayne M: एक संभावित प्रशिक्षण अवसर से कम चिंता का विषय :)
जोएल एथरटन

1

कभी-कभी यह पैटर्न उपयोगी होता है जब आप, कॉल करने वाले को यह ध्यान नहीं रखना चाहिए कि लौटा हुआ प्रकार एक संदर्भ या मान प्रकार है। यदि आप एक मूल्य प्रकार को पुनः प्राप्त करने के लिए इस तरह की विधि को बुला रहे हैं, तो उस मूल्य प्रकार को स्थापित अमान्य मान (जैसे double.NaN) की आवश्यकता होगी, या आपको सफलता का निर्धारण करने के लिए किसी अन्य तरीके की आवश्यकता होगी।


यह समझ आता है। थोड़ा अजीब लगता है, लेकिन यह एक वैध कारण की तरह लगता है।
वेन मोलिना

0

विचार एक मान वापस करने के लिए है जो इंगित करता है कि क्या प्रक्रिया सफल थी, इस तरह कोड की अनुमति देता है:

Baz b;
if (fooObject.foo(id, out b)) {
   // do something with b
}
else {
   Error.screamAndRun("object lookup/whatever failed! AAaAAAH!");
}

यदि ऑब्जेक्ट शून्य नहीं हो सकता (जो आपके उदाहरण में सही प्रतीत होता है), तो यह निम्नानुसार बेहतर है:

Baz b = fooObject.foo(id);
if (b != null) {
   // do something with b
}
else {
   Error.screamAndRun("object lookup/whatever failed! AAaAAAH!");
}

यदि ऑब्जेक्ट अशक्त हो सकता है, तो अपवाद जाने का तरीका है:

try {
   Baz b = fooObject.foo(id);
}
catch (BazException e) {
   Error.screamAndRun("object lookup/whatever failed! AAaAAAH!");
}

यह C में उपयोग किया जाने वाला एक सामान्य पैटर्न है, जहाँ कोई अपवाद नहीं हैं। यह फ़ंक्शन को एक त्रुटि स्थिति वापस करने की अनुमति देता है। अपवाद आम तौर पर एक बहुत क्लीनर समाधान है।


विशेष रूप से कोड के पहले से ही एक अपवाद को फेंकने के बाद से।
डेविड थॉर्नले
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.