क्या शून्य विधि के अंदर रिटर्न का उपयोग करना बुरा है?


92

निम्नलिखित कोड की कल्पना करें:

void DoThis()
{
    if (!isValid) return;

    DoThat();
}

void DoThat() {
    Console.WriteLine("DoThat()");
}

क्या शून्य विधि के अंदर रिटर्न का उपयोग करना ठीक है? क्या इसमें कोई प्रदर्शन दंड है? या इस तरह एक कोड लिखना बेहतर होगा:

void DoThis()
{
    if (isValid)
    {
        DoThat();
    }
}
c#  return  void 

1
क्या के बारे में: शून्य DoThis () {अगर (isValid) DoThat (); }
Dscoduc

30
कोड कल्पना? क्यों? वहीं है! :-D
STW

यह अच्छा सवाल है, मुझे हमेशा लगता है कि क्या रिटर्न का उपयोग करना अच्छा है; विधि या कार्य से बाहर निकलने के लिए। विशेष रूप से एक LINQ डेटा माइनिंग मेथड में कई IQueryable <T> परिणाम होते हैं और ये सभी एक दूसरे पर निर्भर करते हैं। यदि उनमें से एक का कोई परिणाम नहीं है, तो सतर्क और बाहर निकलें।
चेउंग

जवाबों:


173

शून्य विधि में वापसी बुरा नहीं है, घोंसले को कम करने के लिए उल्टे ifबयानों के लिए एक सामान्य अभ्यास है ।

और आपके तरीकों पर कम घोंसले के शिकार होने से कोड की पठनीयता और रखरखाव में सुधार होता है।

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


33

गार्ड का उपयोग करने का एक और बड़ा कारण है (जैसा कि नेस्टेड कोड के विपरीत): यदि कोई अन्य प्रोग्रामर आपके फ़ंक्शन में कोड जोड़ता है, तो वे सुरक्षित वातावरण में काम कर रहे हैं।

विचार करें:

void MyFunc(object obj)
{
    if (obj != null)
    {
        obj.DoSomething();
    }
}

बनाम:

void MyFunc(object obj)
{
    if (obj == null)
        return;

    obj.DoSomething();
}

अब, कल्पना करें कि एक और प्रोग्रामर लाइन जोड़ता है: obj.DoSomethingElse ();

void MyFunc(object obj)
{
    if (obj != null)
    {
        obj.DoSomething();
    }

    obj.DoSomethingElse();
}

void MyFunc(object obj)
{
    if (obj == null)
        return;

    obj.DoSomething();
    obj.DoSomethingElse();
}

जाहिर है कि यह एक सरलीकृत मामला है, लेकिन प्रोग्रामर ने पहले (नेस्टेड कोड) उदाहरण में प्रोग्राम को क्रैश कर दिया है। दूसरे उदाहरण में (गार्ड के साथ जल्दी बाहर निकलना), एक बार जब आप गार्ड से मिल जाते हैं, तो आपका कोड एक अशक्त संदर्भ के अनजाने उपयोग से सुरक्षित होता है।

बेशक, एक महान प्रोग्रामर इस तरह (अक्सर) गलतियाँ नहीं करता है। लेकिन रोकथाम इलाज से बेहतर है - हम कोड को इस तरह से लिख सकते हैं जो त्रुटियों के इस संभावित स्रोत को पूरी तरह से समाप्त कर देता है। नेस्टिंग जटिलता जोड़ती है, इसलिए सर्वोत्तम प्रथाएं नेस्टिंग को कम करने के लिए रिफैक्टिंग कोड की सिफारिश करती हैं।


हां, लेकिन दूसरी तरफ, घोंसले के शिकार की कई परतें, अपनी शर्तों के साथ, कोड को और भी अधिक बग से ग्रस्त कर देती हैं, तर्क को ट्रैक करना अधिक कठिन और - अधिक महत्वपूर्ण रूप से - डीबग करना कठिन। फ्लैट कार्यों में कम बुराई है, आईएमओ।
6

18
मैं कम घोंसले के शिकार के पक्ष में बहस कर रहा हूँ ! :-)
जेसन विलियम्स

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

18

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

एक समान प्रश्न पर प्रतिक्रियाओं की भी जांच करें: क्या मुझे इफ-के बजाय रिटर्न / जारी बयान का उपयोग करना चाहिए?


8

यह बुरा अभ्यास नहीं है (सभी कारणों के लिए जो पहले ही कहा गया है)। हालांकि, आपके पास एक विधि में जितना अधिक रिटर्न होगा, उतनी ही अधिक संभावना छोटे छोटे तार्किक तरीकों में विभाजित होनी चाहिए।


8

पहला उदाहरण एक गार्ड स्टेटमेंट का उपयोग कर रहा है। से विकिपीडिया :

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

मुझे लगता है कि एक विधि के शीर्ष पर गार्ड का एक गुच्छा कार्यक्रम के लिए एक पूरी तरह से समझने योग्य तरीका है। यह मूल रूप से कह रहा है "इस पद्धति को निष्पादित न करें यदि इनमें से कोई भी सत्य है"।

तो सामान्य तौर पर यह इस तरह होगा:

void DoThis()
{
  if (guard1) return;
  if (guard2) return;
  ...
  if (guardN) return;

  DoThat();
}

मुझे लगता है कि यह एक बहुत अधिक पठनीय है:

void DoThis()
{
  if (guard1 && guard2 && guard3)
  {
    DoThat();
  }
}

3

कोई प्रदर्शन जुर्माना नहीं है, हालांकि कोड का दूसरा टुकड़ा अधिक पठनीय है और इसलिए इसे बनाए रखना आसान है।


रसेल मैं आपकी राय से असहमत हूं लेकिन आपको इसके लिए वोट नहीं देना चाहिए था। इसे बाहर करने के लिए +1। Btw, मेरा मानना ​​है कि एक बूलियन टेस्ट और सिंगल लाइन पर एक खाली लाइन के बाद वापसी एक स्पष्ट संकेत है कि क्या चल रहा है। उदाहरण के लिए रोड्रिगो का पहला उदाहरण।
पॉल ससिक

मैं इससे असहमत हूं। बढ़ते घोंसले के शिकार को पठनीयता में सुधार नहीं होता है। कोड का पहला टुकड़ा एक "गार्ड" कथन का उपयोग कर रहा है, जो कि पूरी तरह से समझने योग्य पैटर्न है।
cdmckay

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

2

इस मामले में, आपका दूसरा उदाहरण बेहतर कोड है, लेकिन इसका शून्य फ़ंक्शन से लौटने से कोई लेना-देना नहीं है, यह केवल इसलिए है क्योंकि दूसरा कोड अधिक प्रत्यक्ष है। लेकिन एक शून्य फ़ंक्शन से लौटना पूरी तरह से ठीक है।


0

यह पूरी तरह से ठीक है और कोई 'प्रदर्शन दंड' नहीं है, लेकिन कभी भी ब्रैकेट्स के बिना 'इफ' स्टेटमेंट नहीं लिखना चाहिए।

हमेशा

if( foo ){
    return;
}

यह अधिक पठनीय है; और आप कभी भी गलती से यह नहीं मानेंगे कि कोड के कुछ हिस्से उस विवरण के भीतर हैं जब वे नहीं हैं।


2
पठनीय व्यक्तिपरक है। imho, जो कुछ भी कोड है जो अनावश्यक है उसे कम पठनीय बनाता है ... (मुझे अधिक पढ़ना है, और फिर मुझे आश्चर्य है कि यह क्यों है और यह सुनिश्चित करने के लिए समय बर्बाद कर रहा है कि मैं कुछ याद नहीं कर रहा हूं) ... लेकिन यह मेरा है व्यक्तिपरक राय
चार्ल्स ब्रेटाना

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

2
रेशमी, कृपया अपने से पहले दर्ज करें दबाएँ {। यह आपके {साथ }एक ही कॉलम में आपकी पंक्तियाँ बनाता है, जो पठनीयता को बहुत अधिक एड्स करता है (इसी खुले / करीब ब्रेसिज़ को खोजने के लिए बहुत आसान)।
इमेजिस्ट

1
@ मैं व्यक्तिगत प्राथमिकता के लिए छोड़ दूँगा; और यह मेरे द्वारा पसंद किए जाने का तरीका है :)
नोन सिल्क

1
यदि हर क्लोज़-ब्रेस का मिलान एक खुले-ब्रेस के साथ किया जाता है, जिसे इंडेंट के समान स्तर पर रखा जाता है , तो नेत्रहीन रूप से प्रतिष्ठित होने वाले ifस्टेटमेंट्स के लिए क्लोज़ ब्रेसेस की आवश्यकता होगी, और इस प्रकार ifस्टेटमेंट कंट्रोल करने से एक स्टेटमेंट सुरक्षित रहेगा। ओपन-ब्रेस ifको प्रत्येक मल्टी-स्टेटमेंट पर वर्टिकल स्पेस की एक लाइन के साथ लाइन में वापस पुश करना if, लेकिन एक अन्यथा-अनावश्यक क्लोज़-ब्रेस लाइन का उपयोग करने की आवश्यकता होगी।
सुपरकैट

0

मैं इस एक पर आप सभी युवा व्हिपसैपर्स से असहमत होने जा रहा हूं।

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

मूल नियम यह है कि प्रत्येक नियंत्रण संरचना, और प्रत्येक मॉड्यूल में एक प्रविष्टि और एक निकास होना चाहिए। मॉड्यूल के बीच में एक स्पष्ट वापसी उस नियम को तोड़ती है, और यह कार्यक्रम की स्थिति के बारे में तर्क करने के लिए बहुत कठिन बनाता है, जो बदले में यह कहना मुश्किल है कि कार्यक्रम सही है या नहीं (जो कि अधिक मजबूत संपत्ति है "चाहे वह काम करता हो या नहीं")।

1970 के दशक की "संरचित प्रोग्रामिंग" क्रांति से "GOTO स्टेटमेंट को माना हानिकारक" और "संरचित प्रोग्रामिंग" को लात मार दी। उन दो टुकड़ों के कारण हमारे पास हैं अगर-तब-तब, जबकि-और अन्य स्पष्ट नियंत्रण निर्माण आज, और क्यों उच्च स्तर की भाषाओं में गोटो बयान लुप्तप्राय प्रजातियों की सूची में हैं। (मेरी निजी राय है कि उन्हें विलुप्त प्रजाति सूची में होना चाहिए।)

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

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


2
@ जॉन: हम पास्कल (हम में से अधिकांश, वैसे भी) के समय के बारे में कई बार रिटर्न के बारे में डायस्क्रा निषेध से अधिक हो गए।
जॉन सॉन्डर्स

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

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

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

@ जैसन: मूल प्रश्न विशेष रूप से गार्ड स्टेटमेंट के बारे में नहीं था, बल्कि एक विधि के बीच में यादृच्छिक रिटर्न स्टेटमेंट के बारे में था। उदाहरण दिया गया उदाहरण गार्ड होने के लिए प्रकट होता है। मुख्य मुद्दा यह है कि, वापसी स्थल पर, आप इस बात के लिए सक्षम होना चाहते हैं कि विधि ने क्या किया या क्या नहीं किया, और रैंडम रिटर्न उतना ही कठिन है, वास्तव में उन्हीं कारणों से जो यादृच्छिक गोटो इसे कठिन बनाते हैं। देखें: दिज्क्स्त्र, "गोटो स्टेटमेंट कंसीडरेड हार्मफुल"। सिंटैक्स पक्ष पर, cdmckay ने एक अन्य उत्तर में, गार्ड के लिए उनका पसंदीदा सिंटैक्स; मैं उनकी राय से असहमत हूं कि कौन सा रूप अधिक पठनीय है।
जॉन आर। स्ट्रॉह्म

0

गार्ड का उपयोग करते समय, सुनिश्चित करें कि आप पाठकों को भ्रमित न करने के लिए कुछ दिशानिर्देशों का पालन करते हैं।

  • फ़ंक्शन एक काम करता है
  • गार्ड को केवल फ़ंक्शन में पहले तर्क के रूप में पेश किया जाता है
  • unnested हिस्सा समारोह के शामिल कोर आशय

उदाहरण

// guards point you to the core intent
void Remove(RayCastResult rayHit){

  if(rayHit== RayCastResult.Empty)
    return
    ;
  rayHit.Collider.Parent.Remove();
}

// no guards needed: function split into multiple cases
int WonOrLostMoney(int flaw)=>
  flaw==0 ? 100 :
  flaw<10 ? 30 :
  flaw<20 ? 0 :
  -20
;

-3

जब वस्तु अशक्त हो तो कुछ भी न लौटाने के बजाय अपवाद फेंक दें।

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

लेकिन जल्दी वापसी अन्यथा बुरा अभ्यास नहीं है।


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