एक IF स्टेटमेंट प्राप्त करना


39

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

मान लें कि मेरे पास यह कोड है:

foreach (someObject in someObjectList) 
{
    if(someObject != null) 
    {
        someOtherObject = someObject.SomeProperty;
    }
}

और ReSharper सुझाव देगा कि मैं ऐसा करता हूं:

foreach (someObject in someObjectList)
{
    if(someObject == null) continue;
    someOtherObject = someObject.SomeProperty;
}

ऐसा लगता है कि ReSharper ALWAYS सुझाव देगा कि मैं IFs को उल्टा कर दूं, चाहे कितना भी नेस्टिंग हो। यह समस्या यह है कि मुझे कम से कम कुछ स्थितियों में घोंसला बनाना पसंद है। मेरे लिए पढ़ना आसान है और यह पता लगाना आसान है कि कुछ जगहों पर क्या हो रहा है। यह हमेशा मामला नहीं होता है, लेकिन मैं कभी-कभी अधिक आरामदायक घोंसले के शिकार महसूस करता हूं।

मेरा सवाल है: व्यक्तिगत पसंद या पठनीयता के अलावा, क्या घोंसला कम करने का कोई कारण है? क्या कोई प्रदर्शन अंतर या कुछ और है जिसकी मुझे जानकारी नहीं है?



24
यहाँ महत्वपूर्ण बात यह है कि "पुनर्विक्रेता संकेत"। सुझाव पर एक नज़र डालें, अगर यह कोड को पढ़ना आसान बनाता है और सुसंगत है, तो इसका उपयोग करें। यह प्रत्येक लूप के लिए / के साथ समान कार्य करता है।
जॉन रेन्नोर

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

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

2
क्या ReSharper भी सुझाव को सशर्त स्थानांतरित करने का सुझाव नहीं देता है? foreach (someObject in someObjectList.Where (ऑब्जेक्ट => ऑब्जेक्ट! = null)) {...}
रोमन रेनर

जवाबों:


63

निर्भर करता है। आपके उदाहरण में गैर-उल्टे ifकथन का होना कोई समस्या नहीं है, क्योंकि शरीर का आकार ifबहुत छोटा है। हालाँकि आप आमतौर पर उन बयानों को पलटना चाहते हैं जब शरीर बढ़ता है।

हम केवल इंसान हैं और एक समय में कई चीजें अपने सिर पर रखना मुश्किल है।

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


64
मैं डेवलपर राय के ज्वार को इस तरह से देखना पसंद करता हूं। कोड में बहुत अधिक घोंसले के शिकार हैं क्योंकि एक असाधारण लोकप्रिय भ्रम है कि break, continueऔर कई returnसंरचित नहीं हैं।
जिमीजम्स

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

2
@ ईवान: 'इस कैंट बी x के बीच क्या अंतर है या यह शीर्ष पर पाश से बाहर निकल गया होगा' और 'यह एक्स नहीं हो सकता है या यह इस ब्लॉक में प्रवेश नहीं करेगा'?
Collin

कुछ भी एक्स की जटिलता और अर्थ नहीं है जो महत्वपूर्ण है
इवान

4
@Ewan: मुझे लगता है break/ continue/ returnएक के ऊपर एक वास्तविक लाभ है elseब्लॉक। जल्दी आउट होने के साथ, 2 ब्लॉक हैं : गेट -आउट ब्लॉक और स्टे ब्लॉक; साथ elseदेखते हैं 3 ब्लॉक : अगर, और, और जो बाद आता है (जो जो कुछ भी शाखा लिया प्रयोग किया जाता है)। मैं कम ब्लॉक रखना पसंद करता हूं।
मैथ्यू एम।

33

नकारात्मक बातों से बचें। जब सीपीयू उनसे प्यार करता है तब भी मनुष्य उन्हें चूसता है।

हालाँकि, मुहावरों का सम्मान करें। हम इंसान आदत के प्राणी हैं इसलिए हम मातम से भरे सीधे रास्तों को अच्छी तरह से पहनना पसंद करते हैं।

foo != null, दुख की बात है, एक मुहावरा बन गया है। मैं मुश्किल से अलग भागों को अब नोटिस करता हूं। मैं इसे देखता हूं और बस सोचता हूं, "ओह, यह fooअब से डॉट करना सुरक्षित है "।

यदि आप उस पलटना चाहते हैं (ओह, किसी दिन, कृपया) आपको एक बहुत मजबूत मामले की आवश्यकता है। आपको कुछ ऐसा चाहिए, जो मेरी आँखों को अनायास उसकी ओर सरकने दे और उसे एक पल में समझ ले।

हालाँकि, आपने हमें क्या दिया:

foreach (someObject in someObjectList)
{
    if(someObject == null) continue;
    someOtherObject = someObject.SomeProperty;
}

जो संरचनात्मक रूप से भी समान नहीं है!

foreach (someObject in someObjectList)
{
    if(someObject == null) continue;
    someOtherObject = someObject.SomeProperty;

    if(someGlobalObject == null) continue;
    someSideEffectObject = someGlobalObject.SomeProperty;
}

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

क्षमा करें, हो सकता है कि ReSharper इस 90% समय का सुझाव देने के लिए सही हो, लेकिन अशक्त जांच में मुझे लगता है कि आपने एक कोने का मामला ढूंढ लिया है, जहां इसे सबसे अच्छा अनदेखा किया गया है। उपकरण केवल आपको पढ़ाने में अच्छा नहीं है कि पठनीय कोड क्या है। एक मानव से पूछो। एक सहकर्मी की समीक्षा करें। लेकिन आँख बंद करके उपकरण का पालन न करें।


1
ठीक है, अगर आपके पास लूप में अधिक कोड है, तो यह कैसे काम करता है यह इस बात पर निर्भर करता है कि यह सब एक साथ कैसे आता है। यह स्वतंत्र कोड नहीं है। प्रश्न में रिफलेक्टेड कोड उदाहरण के लिए सही था, लेकिन सही नहीं हो सकता जब अलगाव में न हो - क्या वह बिंदु था जिसके लिए आप जा रहे थे? (हालांकि नकारात्मक से बचने के लिए नहीं +1)
बाल्ड्रिक

@Baldrickk if (foo != null){ foo.something() }मुझे परवाह किए बिना कोड जोड़ने की अनुमति देता है अगर fooअशक्त था। यह नहीं है यहां तक ​​कि अगर मुझे ऐसा करने की आवश्यकता नहीं है, तो अब मैं यह कहकर भविष्य को खराब करने के लिए प्रेरित नहीं करता हूं कि "अच्छी तरह से वे इसे ठीक कर सकते हैं यदि उन्हें जरूरत है"। Feh। सॉफ्टवेयर केवल सॉफ्ट है अगर इसे बदलना आसान है।
कैंडिड_ऑरेंज

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

संबंधित और intertwined एक ही बात नहीं कर रहे हैं।
कैंडिड_ओरेंज

1
नकारात्मक
बातों

20

यह इस बारे में पुरानी दलील है कि क्या ब्रेकिंग नेस्टिंग बदतर है।

लोग पैरामीटर चेक के लिए जल्दी वापसी स्वीकार करते हैं, लेकिन इसके एक विधि के थोक में पर आधारित है।

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

foreach (someObject in someObjectList.where(i=>i != null))
{
    someOtherObject = someObject.SomeProperty;
}

स्पष्ट रूप से घोंसले के शिकार के लिए चीजों का पालन करना मुश्किल हो जाता है जब आपके पास कई परतें होती हैं

foreach (someObject in someObjectList) 
{
    if(someObject != null) 
    {
        someOtherObject = someObject.SomeProperty;
        if(someObject.x > 5) 
        {
            x ++;
            if(someObject.y > 5) 
            {
                x ++;
            }
        }
    }
}

सबसे बुरा तब है जब आपके पास दोनों हैं

foreach (someObject in someObjectList) 
{
    if(someObject != null) 
    {
        someOtherObject = someObject.SomeProperty;
        if(someObject.x > 5) 
        {
            x ++;
            if(someObject.y > 5) 
            {
                x ++;
                return;
            }
            continue;
        }
        someObject.z --;
        if(myFunctionWithSideEffects(someObject) > 6) break;
    }
}

11
इस लाइन से प्यार करें: foreach (subObject in someObjectList.where(i=>i != null))पता नहीं क्यों मैंने कभी ऐसा कुछ नहीं सोचा।
बैरी फ्रैंकलिन

@BarryFranklin ReSharper के पास "कन्वर्ट करने के लिए LINQ-अभिव्यक्ति" के साथ एक हरे रंग की बिंदीदार अंडरलाइन होनी चाहिए, क्योंकि यह सुझाव है कि आपके लिए ऐसा करेगा। ऑपरेशन के आधार पर, यह अन्य लाइन विधियों जैसे कि Sum या Max को भी कर सकता है।
केविन शुल्क

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

विडंबना यह है कि पुनर्विक्रेता द्वारा संपादित करने के लिए घोंसले के समान स्तर हैं, क्योंकि इसमें एक-लाइनर द्वारा पीछा करने पर भी है।
पीटर

हालांकि, कोई ब्रेसिज़ नहीं! जिसे स्पष्ट रूप से अनुमति दी गई है: /
इवान

6

इसके साथ परेशानी यह continueहै कि यदि आप कोड में अधिक रेखाएँ जोड़ते हैं तो तर्क जटिल हो जाता है और इसमें कीड़े होने की संभावना होती है। जैसे

foreach (someObject in someObjectList)
{
    if(someObject == null) continue;
    someOtherObject = someObject.SomeProperty;

    ...  imagine that there is some code here ...

    // added later by a Junior Developer
    doSomeOtherFunction(someObject);
}

आप कॉल करना चाहते हैं doSomeOtherFunction()के लिए सभी someObject, या केवल यदि गैर-शून्य? मूल कोड के साथ आपके पास विकल्प है और यह स्पष्ट है। के साथ continueएक भूल हो सकती है "ओह, हाँ, वापस वहाँ हम nulls छोड़ दिया" और आप यह भी विकल्प है कि आप इसे किसी तरह के लिए कॉल न करें, जब तक कि आप उस कॉल को विधि की शुरुआत में न करें जो संभव नहीं है या सही नहीं है अन्य कारणों से।

हां, बहुत से घोंसले के शिकार बदसूरत हैं और संभवतः भ्रमित हैं, लेकिन इस मामले में मैं पारंपरिक शैली का उपयोग करता हूं।

बोनस प्रश्न: उस सूची में अशक्तियां क्यों हैं जिनके साथ शुरू करना है? यह बेहतर होगा कि पहली जगह में कभी भी अशक्त न हो, इस मामले में प्रसंस्करण तर्क बहुत सरल है।


12
लूप के अंदर पर्याप्त कोड नहीं होना चाहिए जिसे आप बिना स्क्रॉल किए नल के शीर्ष पर देख सकते हैं।
ब्रायन बोएचर

@Bryan Boettcher सहमत हैं, लेकिन सभी कोड इतनी अच्छी तरह से नहीं लिखे गए हैं। और यहां तक ​​कि जटिल कोड की कई पंक्तियों को जारी रखने के बारे में (या गलतफहमी) हो सकती है। व्यवहार में मैं ठीक हूं returnक्योंकि वे "क्लीन ब्रेक" बनाते हैं, लेकिन IMO breakऔर continueभ्रम की स्थिति पैदा करते हैं और ज्यादातर मामलों में, सबसे अच्छा बचा जाता है।
user949300

4
@ user949300 दस साल के विकास के बाद, मैंने कभी भी तोड़ नहीं पाया या भ्रम पैदा करना जारी रखा। मैंने उन्हें भ्रम में डाल दिया है, लेकिन वे कभी इसका कारण नहीं रहे। आमतौर पर, डेवलपर के खराब फैसले इसका कारण होते थे, और वे भ्रम का कारण बनते थे कि वे किस हथियार का इस्तेमाल करते हैं।
corsiKa

1
@corsiKa Apple SSL बग वास्तव में एक गोटो बग है, लेकिन आसानी से एक ब्रेक या बग जारी रख सकता है। हालाँकि कोड भयानक है ...
user949300

3
@BryanBoettcher समस्या मुझे लगती है कि वही देव जो सोचते रहते हैं या एकाधिक रिटर्न ठीक हैं, उन्हें भी लगता है कि बड़े विधि निकायों में उन्हें दफनाना भी ठीक है। इसलिए प्रत्येक अनुभव जो मेरे पास जारी है / एकाधिक रिटर्न कोड के बड़े पैमाने पर है।
एंडी

3

विचार जल्दी वापसी है। प्रारंभिक returnएक पाश में जल्दी हो जाता है continue

इस सवाल पर बहुत अच्छे जवाब: क्या मुझे एक समारोह से जल्दी लौटना चाहिए या एक बयान का उपयोग करना चाहिए?

ध्यान दें कि प्रश्न के आधार पर राय के रूप में बंद होने पर, 430+ वोट शुरुआती रिटर्न के पक्ष में हैं, ~ 50 वोट "यह निर्भर करता है", और 8 प्रारंभिक रिटर्न के खिलाफ हैं। इसलिए एक असाधारण मजबूत आम सहमति है (या तो वह है, या मैं गिनती में बुरा हूं, जो प्रशंसनीय है)।

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


2

यह तकनीक पूर्व स्थितियों को प्रमाणित करने के लिए उपयोगी है जब आपकी स्थिति का मुख्य थोक तब होता है जब उन शर्तों को पूरा किया जाता है।

हम अक्सर ifsअपने काम में उल्टे रहते हैं और किसी अन्य व्यक्ति को नियुक्त करते हैं। यह बहुत बार-बार हुआ करता था कि एक पीआर की समीक्षा करते समय मैं यह बता सकता था कि मेरे सहकर्मी घोंसले के तीन स्तरों को कैसे हटा सकते हैं! यह कम बार होता है क्योंकि हम अपने आईएफ को रोल आउट करते हैं।

यहाँ एक खिलौने का उदाहरण है जिसे लुढ़काया जा सकता है

function foobar(x, y, z) {
    if (x > 0) {
        if (z != null && isGamma(y)) {
            // ~10 lines of code
            // return something
        }
        else {
           return y
        }
    }
    else {
      return y + z
    }
}

इस तरह कोड, जहां एक दिलचस्प मामला है (जहां बाकी बस रिटर्न या छोटे स्टेटमेंट ब्लॉक हैं) आम हैं। उपरोक्त को फिर से लिखना तुच्छ है

function foobar(x, y, z) {
    if (x <=0) {
        return y + z
    }
    if (z == null || !isGamma(y) {
       return y
    }
    // ~ 10 lines of code
    // return something
}

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


ओपी के कोड सैंपल के जवाब में, मैं यह कहता हूं कि यह एक बहुत बड़ा पतन है। विशेष रूप से 1TB में, मैं जिस शैली का उपयोग करता हूं, उलटा कोड के कारण आकार में वृद्धि होती है।


0

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

अन्य सभी चीजें समान हैं, कम घोंसले के शिकार बेहतर है, यही वजह है कि ReSharper एक परिवर्तन का सुझाव देगा जो घोंसले के शिकार को कम करता है। लेकिन अन्य सभी चीजें समान नहीं हैं : इस मामले में परिवर्तन के लिए एक परिचय की आवश्यकता होती है continue, जिसका अर्थ है कि परिणामी कोड वास्तव में पालन करना कठिन है।

में कुछ मामलों में, एक के लिए घोंसले के स्तर का आदान प्रदान continue कर सकता है वास्तव में एक सुधार हो, लेकिन इस सवाल में कोड है, जो ReSharpers यांत्रिक नियमों की समझ से परे है के शब्दों पर निर्भर करता है।

आपके मामले में ReSharper सुझाव कोड को बदतर बना देगा। तो बस इसे नजरअंदाज करें। या बेहतर: सुझाए गए परिवर्तन का उपयोग न करें, लेकिन कोड को कैसे बेहतर बनाया जा सकता है, इस बारे में थोड़ा विचार करें। ध्यान दें कि आप एक ही चर को कई बार असाइन कर सकते हैं, लेकिन केवल अंतिम असाइनमेंट का प्रभाव होता है, क्योंकि पिछले को केवल ओवरराइट किया जाएगा। यह करता है एक बग की तरह देखो। ReSharpers सुझाव बग को ठीक नहीं करता है, लेकिन यह इसे थोड़ा स्पष्ट करता है कि कुछ संदिग्ध तर्क चल रहा है।


0

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

for(obj in objectList) {
    if(obj == null) continue;
    if(obj.getColour().equals(Color.BLUE)) {
        // Handle blue objects
    } else {
        // Handle non-blue objects
    }
}

ध्यान दें कि जावा स्ट्रीम या अन्य कार्यात्मक मुहावरों में, आप लूपिंग से फ़िल्टरिंग को अलग कर सकते हैं, उपयोग करके:

items.stream()
    .filter(i -> (i != null))
    .filter(i -> i.getColour().equals(Color.BLUE))
    .forEach(i -> {
        // Process blue objects
    });

संयोग से, यह उन चीजों में से एक है जो मैं पर्ल के बारे में प्यार करता हूं अगर ( unless) एकल बयानों पर लागू होता है, जो निम्न प्रकार के कोड की अनुमति देता है, जो मुझे पढ़ने में बहुत आसान लगता है:

foreach my $item (@items) {
    next unless defined $item;
    carp "Only blue items are supported! Failed on item $item" 
       unless ($item->get_colour() eq 'blue');
    ...
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.