कोड अनुबंध / दावा: डुप्लिकेट चेक के साथ क्या?


10

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

उदाहरण स्थिति: मैं पहली बार निम्नलिखित फ़ंक्शन लिखता हूं

void DoSomething( object obj )
{
  Contract.Requires<ArgumentNullException>( obj != null );
  //code using obj
}

फिर कुछ घंटों बाद मैं एक और फ़ंक्शन लिखता हूं जो पहले कॉल करता है। जैसा कि सब कुछ अभी भी स्मृति में ताजा है, मैं अनुबंध को डुप्लिकेट नहीं करने का निर्णय लेता हूं, क्योंकि मुझे पता है कि DoSomethingपहले से ही एक अशक्त वस्तु के लिए wil चेक:

void DoSomethingElse( object obj )
{
  //no Requires here: DoSomething will do that already
  DoSomething( obj );
  //code using obj
}

स्पष्ट समस्या: DoSomethingElseअब DoSomethingयह पुष्टि करने के लिए निर्भर करता है कि obj अशक्त नहीं है। तो DoSomethingकभी भी अब और नहीं जाँचने का निर्णय लेना चाहिए , या यदि मैं किसी अन्य फ़ंक्शन का उपयोग करने का निर्णय लेता हूँ तो शायद अब और जाँच नहीं की जाए। जो मुझे इस कार्यान्वयन को लिखने के लिए आगे ले जाता है:

void DoSomethingElse( object obj )
{
  Contract.Requires<ArgumentNullException>( obj != null );
  DoSomething( obj );
  //code using obj
}

हमेशा सुरक्षित, कोई चिंता नहीं, सिवाय इसके कि यदि स्थिति बढ़ती है तो एक ही वस्तु को कई बार जांचा जा सकता है और यह दोहराव का एक रूप है और हम सभी जानते हैं कि यह इतना अच्छा नहीं है।

इन जैसी स्थिति के लिए सबसे आम अभ्यास क्या है?


3
ArgumentBullException? यह एक नया है :)
एक CVn

lol @ मेरा टाइपिंग कौशल ... मैं इसे संपादित करूँगा।
13

जवाबों:


13

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

तो ऊपर आपके उदाहरण में, अगर doSomethingElse () को objference की आवश्यकता नहीं है तो मैं वहाँ null के लिए obj जाँच नहीं करूँगा।

यदि DoSomething () dereference obj करता है तो इसे null के लिए जाँचना चाहिए।

यदि दोनों कार्य इसे रोकते हैं तो उन्हें दोनों की जांच करनी चाहिए। इसलिए यदि DoSomethingElse dereferences आब्जर्व करते हैं तो इसे null के लिए जांचना चाहिए, लेकिन DoSomething को अभी भी null के लिए जांचना चाहिए क्योंकि इसे किसी अन्य पथ से कॉल किया जा सकता है।

इस तरह आप कोड को काफी साफ छोड़ सकते हैं और फिर भी गारंटी दे सकते हैं कि चेक सही जगह पर हैं।


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

2

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

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

आपके दिए गए उदाहरण में, DoSomethingElse()फ़ंक्शन अनुबंध के अनुसार निर्दिष्ट नहीं रहता है DoSomething(), क्योंकि अशक्त पारित किया जा सकता है, और स्थिर चेकर इस समस्या का संकेत देगा। इसे हल करने का तरीका उसी अनुबंध को जोड़कर है DoSomethingElse()

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

इससे आपको पुनर्विचार करना चाहिए कि आप व्यवहार को दो कार्यों में विभाजित क्यों करते हैं। यह हमेशा से मेरी राय रही है ( लोकप्रिय धारणा के विपरीत ) कि आपको उन कार्यों को विभाजित नहीं करना चाहिए जो केवल एक ही स्थान से कहे जाते हैं । अनुबंधों को लागू करके इनकैप्सुलेशन को उजागर करने से यह और भी स्पष्ट हो जाता है। ऐसा लगता है कि मुझे अपने कारण के लिए एक अतिरिक्त तर्क मिला! धन्यवाद! :)


आपके अंतिम पैराग्राफ के बारे में: वास्तविक कोड में दोनों फ़ंक्शन दो अलग-अलग वर्गों के सदस्य थे, यही वजह है कि वे विभाजित हैं। इसके अलावा, मैं कई बार निम्न स्थिति में था: एक लंबा कार्य लिखें, इसे विभाजित न करने का निर्णय लें। बाद में पता लगा कि कुछ तर्क कहीं और नकल किए गए हैं, इसलिए इसे किसी भी तरह विभाजित करें। या एक साल बाद इसे फिर से पढ़ें और इसे अपठनीय समझें, इसलिए इसे किसी भी तरह विभाजित करें। या डिबगिंग करते समय: F10 कुंजी पर विभाजित कार्य = कम धमाके। अधिक कारण हैं, इसलिए व्यक्तिगत रूप से मैं विभाजन करना पसंद करता हूं, भले ही इसका मतलब है कि यह कभी-कभी बहुत चरम हो सकता है।
stijn

(1) "बाद में पता चलता है कि कुछ तर्क कहीं और दोहराए जाते हैं" । यही कारण है कि मुझे केवल विभाजन कार्य करने की तुलना में "एपीआई की ओर विकसित" हमेशा अधिक महत्वपूर्ण लगता है। न केवल वर्तमान वर्ग के भीतर, बल्कि पुन: उपयोग के बारे में सोचें। (२) "या एक साल बाद इसे फिर से पढ़ें और इसे अपठनीय समझें" क्योंकि फ़ंक्शन के नाम हैं यह बेहतर है? आपके पास और भी पठनीयता है अगर आप मेरे कोड पर वर्णित " टिप्पणी " कोड पैराग्राफ का उपयोग करते हैं। (3) "विभाजन कार्य = F10 कुंजी पर कम धमाकेदार" ... मैं नहीं देखता कि क्यों।
स्टीवन ज्यूरिस

(1) सहमत (2) पठनीयता व्यक्तिगत प्राथमिकता है इसलिए मेरे लिए वास्तव में चर्चा के तहत कुछ नहीं है .. (3) 20 लाइनों के एक समारोह से गुजरने के लिए F10 को 20 बार मारने की आवश्यकता होती है। विभाजन फ़ंक्शन में उन पंक्तियों में से 10 लाइनों के माध्यम से जाने के लिए मुझे केवल F10 के 11 बार हिट करने की पसंद की आवश्यकता होती है। हां, पहले मामले में मैं ब्रेकपॉइंट लगा सकता हूं या 'जंप्ट टू कर्सर' चुन सकता हूं लेकिन यह दूसरे मामले की तुलना में अभी भी अधिक प्रयास है।
टिजिन

@stijn: (2) सहमत; p (3) स्पष्ट करने के लिए धन्यवाद!
स्टीवन ज्यूरिस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.