2010-05-20 13 views
7

स्थानों पर जहां मैं वैध संकेत के लिए जाँच से पहले मैं उनके साथ एक कार्रवाई करने के हैं; इन चेकों को कभी-कभी बहुत गहराई से घोंसला जा सकता है।नेस्टेड अगर (x) चेक - इसे लिखने का बेहतर तरीका?

उदाहरण के लिए, मुझे लगता है मैं वास्तव में इस के रूप को पसंद नहीं है

if (a) 
{ 
    if (a->b()) 
    { 
    if (a->b()->c()) 
    { 
     a->b()->c()->DoSomething(); 
    } 
    } 
} 

है। क्या इसे कुछ और पठनीय में बदलने का कोई तरीका है? आदर्श रूप से,

if (a && a->b() && a->b()->c()) 
{ 
... 
} 

बहुत अच्छा होगा, लेकिन स्पष्ट रूप से काम नहीं करेगा।

संपादित करें - उदाहरण है कि मैं डाल काम करता है के रूप में सभी ने कहा है NVM। मैंने यह देखने के लिए परीक्षण किया कि यह काम करता है, लेकिन मेरे परीक्षण में मेरे कोड में एक बग था। ओह!

+6

वह काम क्यों नहीं करेगा? –

+3

यह स्पष्ट रूप से * आपके द्वारा पोस्ट किए गए उदाहरण में काम करेगा। क्या आपके द्वारा छोड़े गए 'अन्य' मामलों में कुछ हो रहा है? –

+2

आपको क्या लगता है कि काम नहीं करेगा? शॉर्ट-सर्किट मूल्यांकन बहुत अधिक गारंटी देता है कि दोनों का मतलब एक ही बात है (जब तक कि आपने 'ऑपरेटर और' 'ओवरलोड नहीं किया हो)। –

उत्तर

28

बाद काम क्यों नहीं होता?

सी में, & & एक शॉर्ट-सर्किट ऑपरेटर है, इसलिए इसका मूल्यांकन बाएं से दाएं से किया जाता है, और यदि कोई मूल्यांकन गलत है, तो मूल्यांकन बंद हो जाता है।

वास्तव में, आप लिख सकते हैं:

a && a->b() && a->b()->c() && a->b()->c()->DoSomething(); 
+6

चाहे आप 'a && a-> b() && a-> b() -> c() && a-> b() -> c() -> DoSomething(); 'रिटर्न प्रकार पर निर्भर करता है 'DoSomething'' का। यदि 'DoSomething' शून्य लौटाता है, तो यह कानूनी नहीं है। –

+0

@R सैमुअल क्लैचको: यह केवल तभी लागू होगा जब आप अभिव्यक्ति को 'if' कथन में डाल दें, है ना? ... व्हर्लविंड के उदाहरण में कोई ज़रूरत नहीं है। –

+0

@Daniel - नहीं, क्योंकि यह एक & amp ऑपरेटर का आरएचएस है, इसमें * कुछ * मान होना चाहिए। एक शून्य कार्य वैध आरएचएस नहीं है। – nsayer

5

आपका दूसरे उदाहरण C/C++ काम करता है। यह पहला सर्किट होता है जब पहला गलत मूल्य हिट होता है।

+0

यह जावा में भी काम करता है। – nsayer

+0

@nsayer: हाँ। अच्छी बात। उद्धरण के लिए –

3

क्यों 'स्पष्ट रूप से कार्य नहीं करेगा'? चूंकि && ऑपरेटर केवल सही अवधि का मूल्यांकन करता है, तो बाईं मान्य है, फिर से लिखने के लिए पूरी तरह से सुरक्षित है।

13

से K&R का हवाला देते हुए:

भाव && या || से जुड़े हुए बाएं से दाएं मूल्यांकन किया जाता है, और यह गारंटी है कि मूल्यांकन सत्य के रूप में जैसे ही बंद हो जाएगा या झूठ जाना जाता है।

इसलिए बाद वाला उदाहरण WhirlWind has noted के रूप में पूरी तरह से काम करेगा।


The C Programming Language, द्वितीय संस्करण, पृष्ठ 21.

+0

धन्यवाद। मैंने बिल्कुल इस तरह की चीज के लिए गुगल करने की कोशिश की लेकिन मुझे पता नहीं था कि Google के लिए कौन से शब्द हैं। कहने की जरूरत नहीं है, मुझे यह नहीं मिला, और जब मैंने यह जांचने के लिए खुद का परीक्षण किया कि क्या यह बाएं से दाएं का मूल्यांकन करता है, तो वहां एक बग था जिसने इसे दुर्घटनाग्रस्त कर दिया। – Will

2

if (a && a->b() && a->b()->c()) { a->b()->c()->DoSomething(); }

सी ++ आलसी मूल्यांकन करता है तो यह काम करेंगे। सबसे पहले, मूल्यांकन किया जाएगा और यदि यह 0 है तो पूरी स्थिति झूठी है इसलिए अन्य भागों का कोई मूल्यांकन नहीं होगा।

यह रूप में अच्छी तरह || ऑपरेटर के लिए काम करता है। यदि आप if (a || b) लिखते हैं, तो बी का मूल्यांकन नहीं किया जाएगा यदि कोई सत्य है।

4

आपने अन्य उत्तरों से देखा है कि & & का उपयोग करेगा, और एक शून्य सूचक का सामना करने पर मूल्यांकन को शॉर्ट-सर्किट करेगा।

मेरे जैसे असहज प्रोग्रामर इस तरह के परीक्षणों के लिए दोहराव विधि कॉल से बचने के लिए पसंद करते हैं क्योंकि इससे चिंता करने से बचा जाता है या नहीं।एक विकल्प यह

A* a; 
B* b; 
C* c; 

if ((a=a()) && (b=a->b()) && (c=b->c())) { 
    c->doSomething(); 
} 

वैसे वर्बोज़ और थोड़ा भद्दा तरह के पुनर्लेखन के लिए है, लेकिन कम से कम आप जानते हैं कि प्रत्येक विधि सिर्फ एक बार कहा जाता है।

+0

यदि 'ए' एक सूचक है, तो इसका उपयोग करके आमंत्रण 'a-> b() 'होना चाहिए? –

+0

डी ओह - हाँ। मेरा यही मतलब था, लेकिन लिखा नहीं था। मैं बहुत लंबे समय तक जावा कर रहा हूं ... – mdma

0

दूसरा काम करेगा, बशर्ते आप केवल DoSomething() पर कॉल करना चाहते हैं।

3

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

a->CDoSomething(); 
+1

[डेमेटर का कानून] (http://en.wikipedia.org/wiki/Law_of_Demeter) –

3

श्रृंखलन काम करता है, लेकिन यह जरूरी नहीं कि सबसे अच्छा सामान्य मामले जवाब नहीं है, विशेष रूप से, क्योंकि यह असफलता बिंदु अस्पष्ट करता है। मैं इसके बजाय तर्क को घुमाकर परीक्षणों को झुकाव का सुझाव दूंगा ताकि यह विफलता से निकल सके।

if (!pa) 
    return Fail("No pa"); 

B* pb = pa->b(); 
if (!pb) 
    return Fail("No pb"); 

C* pc = b->c(); 
if (!pc) 
    return Fail("No pc"); 

pc->DoSomething(); 

वही बात, लेकिन फ्लैट और पढ़ने में आसान। इसके अलावा, क्योंकि यह तुरंत विफलता मामले को संभालता है, जिसे else पर नहीं भेजा जाता है जिसे आप कभी भी लिखने के लिए नहीं मिल सकते हैं।

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

संबंधित मुद्दे