c# - सी#में कथन की गिरावट दर्ज करें?




switch-statement (10)

प्रत्येक ब्लॉक ब्लॉक के बाद ब्रेक जैसे जंप स्टेटमेंट की आवश्यकता होती है, जिसमें अंतिम ब्लॉक भी शामिल है चाहे वह केस स्टेटमेंट या डिफॉल्ट स्टेटमेंट हो। एक अपवाद के साथ, (सी ++ स्विच स्टेटमेंट के विपरीत), सी # एक केस लेबल से दूसरे मामले में एक अंतर्निहित गिरावट का समर्थन नहीं करता है। एक अपवाद यह है कि यदि किसी केस स्टेटमेंट में कोई कोड नहीं है।

- सी # स्विच () दस्तावेज

स्विच कथन की गिरावट switch बनाम प्यार के लिए मेरे व्यक्तिगत प्रमुख कारणों में से एक है if/else if संरचना हो। यहां एक उदाहरण है:

static string NumberToWords(int number)
{
    string[] numbers = new string[] 
        { "", "one", "two", "three", "four", "five", 
          "six", "seven", "eight", "nine" };
    string[] tens = new string[] 
        { "", "", "twenty", "thirty", "forty", "fifty", 
          "sixty", "seventy", "eighty", "ninety" };
    string[] teens = new string[]
        { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
          "sixteen", "seventeen", "eighteen", "nineteen" };

    string ans = "";
    switch (number.ToString().Length)
    {
        case 3:
            ans += string.Format("{0} hundred and ", numbers[number / 100]);
        case 2:
            int t = (number / 10) % 10;
            if (t == 1)
            {
                ans += teens[number % 10];
                break;
            }
            else if (t > 1)
                ans += string.Format("{0}-", tens[t]);
        case 1:
            int o = number % 10;
            ans += numbers[o];

            break;
        default:
            throw new ArgumentException("number");
    }
    return ans;
}

स्मार्ट लोग क्रिंग कर रहे हैं क्योंकि string[] एस को फ़ंक्शन के बाहर घोषित किया जाना चाहिए: ठीक है, वे हैं, यह सिर्फ एक उदाहरण है।

कंपाइलर निम्न त्रुटि के साथ विफल रहता है:

Control cannot fall through from one case label ('case 3:') to another
Control cannot fall through from one case label ('case 2:') to another

क्यूं कर? और क्या इस तरह के व्यवहार को तीनों के बिना प्राप्त करने का कोई तरीका है?


( मैंने उत्तर दिया एक उत्तर की प्रतिलिपि / पेस्ट)

switch माध्यम से switch - किसी case में कोई कोड नहीं होने पर case प्राप्त किया जा सकता है ( case 0 देखें), या विशेष goto case ( case 1 देखें) या goto default ( case 2 देखें) फॉर्म का उपयोग करके प्राप्त किया जा सकता है:

switch (/*...*/) {
    case 0: // shares the exact same code as case 1
    case 1:
        // do something
        goto case 2;
    case 2:
        // do something else
        goto default;
    default:
        // do something entirely different
        break;
}

आप "ब्रेक" जोड़ना भूल गए मामले 3 में बयान। यदि 2 में आपने इसे ब्लॉक में लिखा है। इसलिए इसे आजमाएं:

case 3:            
{
    ans += string.Format("{0} hundred and ", numbers[number / 100]);
    break;
}


case 2:            
{
    int t = (number / 10) % 10;            
    if (t == 1)            
    {                
        ans += teens[number % 10];                
    }            
    else if (t > 1)                
    {
        ans += string.Format("{0}-", tens[t]);        
    }
    break;
}

case 1:            
{
    int o = number % 10;            
    ans += numbers[o];            
    break;        
}

default:            
{
    throw new ArgumentException("number");
}

आप 'गेटो केस लेबल' http://www.blackwasp.co.uk/CSharpGoto.aspx

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


उन्होंने डिज़ाइन द्वारा इस व्यवहार को छोड़ दिया जब यह इच्छा से उपयोग नहीं किया गया था लेकिन समस्याओं का कारण बन गया था।

इसका उपयोग तभी किया जा सकता है जब मामले में कोई बयान नहीं है, जैसे:

switch (whatever)
{
    case 1:
    case 2:
    case 3: boo; break;
}

उन्होंने सी # के लिए स्विच स्टेटमेंट (सी / जावा / सी ++ से) व्यवहार बदल दिया। मुझे लगता है कि तर्क यह था कि लोग गिरने के बारे में भूल गए थे और त्रुटियां हुई थीं। एक पुस्तक जिसे मैंने पढ़ा था, अनुकरण करने के लिए गोटो का उपयोग करने के लिए कहा, लेकिन यह मेरे लिए एक अच्छा समाधान की तरह नहीं लगता है।


बस एक त्वरित नोट जोड़ने के लिए कि ज़ैमरिन के लिए कंपाइलर वास्तव में यह गलत पाया है और यह गिरावट की अनुमति देता है। यह माना गया है, लेकिन जारी नहीं किया गया है। इसे कुछ कोड में खोजा गया जो वास्तव में गिर रहा था और संकलक शिकायत नहीं करता था।


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

पाठ्यक्रम की कोई प्रोग्रामिंग भाषा दो लक्ष्यों की सेवा करती है:

  1. कंप्यूटर को निर्देश प्रदान करें।
  2. प्रोग्रामर के इरादों का एक रिकॉर्ड छोड़ दो।

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

इसके विपरीत, जितनी अधिक भाषा प्रोग्रामर के इरादे को व्यक्त करती है, उस अंतराल के साधनों के बजाए, प्रोग्राम लिखने और रखरखाव के दौरान प्रोग्राम को और अधिक समझा जा सकता है।

अब, switch को हमेशा के बराबर श्रृंखला में परिवर्तित करके संकलित किया जा सकता है if-else ब्लॉक या इसी तरह के, लेकिन इसे एक विशेष आम असेंबली पैटर्न में संकलन की इजाजत देने के रूप में डिज़ाइन किया गया था, जहां कोई मूल्य लेता है, इससे ऑफसेट की गणना करता है (चाहे मूल्य के एक पूर्ण हैश द्वारा अनुक्रमित एक तालिका को देखकर, या मूल्य पर वास्तविक अंकगणित द्वारा)। इस बिंदु पर ध्यान देने योग्य है कि आज, सी # संकलन कभी-कभी समकक्ष में switch कर देगा, और कभी-कभी, हैश-आधारित कूद दृष्टिकोण (और इसी प्रकार सी, सी ++, और तुलनीय वाक्यविन्यास वाली अन्य भाषाओं के साथ) का उपयोग करें।

इस मामले में गिरावट के माध्यम से अनुमति देने के दो अच्छे कारण हैं:

  1. यह स्वाभाविक रूप से वैसे भी होता है: यदि आप निर्देशों के एक सेट में एक कूद तालिका बनाते हैं, और निर्देशों के पहले बैच में से किसी एक प्रकार की कूद या वापसी नहीं होती है, तो निष्पादन केवल अगले बैच में स्वाभाविक रूप से प्रगति करेगा। फॉल-थ्रू की अनुमति देना "बस होता है" अगर आप switch उपयोग करने वाले सी को मशीन कोड का उपयोग करके कूद-टेबल में बदल देते हैं।

  2. असेंबली में लिखे गए कोडर्स पहले ही समकक्ष में इस्तेमाल किए गए थे: असेंबली में हाथ से एक जंप टेबल लिखते समय, उन्हें यह विचार करना होगा कि कोड का दिया गया ब्लॉक वापसी के साथ समाप्त होगा, तालिका के बाहर एक कूद, या बस जारी रहेगा अगले ब्लॉक में। इस प्रकार, कोडर के लिए आवश्यक "प्राकृतिक" होने पर कोडर को एक स्पष्ट break जोड़ना भी होता है।

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

चार दशकों बाद हालांकि, कुछ कारणों से चीजें काफी समान नहीं हैं:

  1. आज सी में कोडर के पास बहुत कम या कोई असेंबली अनुभव नहीं हो सकता है। कई अन्य सी-शैली भाषाओं में कोडर भी कम संभावना है (विशेष रूप से जावास्क्रिप्ट!)। "असेंबली से लोगों का क्या उपयोग किया जाता है" की कोई अवधारणा अब प्रासंगिक नहीं है।
  2. ऑप्टिमाइज़ेशन में सुधार का मतलब है कि switch की संभावना को या तो बदल दिया जा रहा है if-else क्योंकि इसे सबसे अधिक कुशल होने की संभावना समझा जाता था, या फिर कूद-तालिका दृष्टिकोण के विशेष रूप से गूढ़ संस्करण में बदल जाता है। उच्च और निम्न-स्तर के दृष्टिकोण के बीच मैपिंग उतना मजबूत नहीं है जितना कि यह एक बार था।
  3. अनुभव से पता चला है कि गिरावट के माध्यम से अल्पसंख्यक मामला बनता है (सूर्य के कंपाइलर का एक अध्ययन, जो ब्लॉक ब्लॉक के 3% पाया जाता है, उसी ब्लॉक पर कई लेबलों के अलावा गिरावट के माध्यम से उपयोग किया जाता है, और ऐसा माना जाता था कि उपयोग यहां का मतलब यह था कि यह 3% वास्तव में सामान्य से काफी अधिक था)। तो अध्ययन की जाने वाली भाषा आम की तुलना में असामान्य रूप से अधिक आसानी से कैटर्रेड बनाती है।
  4. अनुभव से पता चला है कि गिरावट के माध्यम से उन समस्याओं के स्रोत होते हैं जहां यह गलती से किया जाता है, और ऐसे मामलों में जहां कोड को बनाए रखने वाले किसी व्यक्ति द्वारा सही गिरावट से गुम हो जाता है। यह बाद में गिरावट से जुड़ी बगों के लिए एक सूक्ष्म जोड़ है, क्योंकि यदि आपका कोड पूरी तरह से बग-फ्री है, तो भी आपका फॉल-थ्रू समस्याएं पैदा कर सकता है।

पिछले दो बिंदुओं से संबंधित, के एंड आर के वर्तमान संस्करण से निम्नलिखित उद्धरण पर विचार करें:

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

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

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

और जब आप इसके बारे में सोचते हैं, तो इस तरह का कोड:

switch(x)
{
  case 1:
   foo();
   /* FALLTHRU */
  case 2:
    bar();
    break;
}

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

इस प्रकार, तथ्य यह है कि सी # में फॉल-थ्रू के साथ स्पष्ट होना आवश्यक है, जो कि अन्य सी-शैली भाषाओं में अच्छी तरह से लिखने वाले लोगों को कोई जुर्माना नहीं जोड़ता है, क्योंकि वे पहले से ही अपने पतन के माध्यम से स्पष्ट होंगे।

अंत में, यहां goto का उपयोग पहले से ही सी और अन्य ऐसी भाषाओं से एक मानक है:

switch(x)
{
  case 0:
  case 1:
  case 2:
    foo();
    goto below_six;
  case 3:
    bar();
    goto below_six;
  case 4:
    baz();
    /* FALLTHRU */
  case 5:
  below_six:
    qux();
    break;
  default:
    quux();
}

इस तरह के मामले में जहां हम ब्लॉक को उस मूल्य के अलावा निष्पादित कोड में शामिल करना चाहते हैं, जो कि पिछले ब्लॉक में लाता है, तो हम पहले से ही goto का उपयोग कर रहे हैं। (बेशक, अलग-अलग सशर्तों से बचने के साधन और तरीके हैं लेकिन यह इस प्रश्न से संबंधित सबकुछ के बारे में सच है)। जैसे कि सी # एक परिस्थिति से निपटने के पहले से ही सामान्य तरीके से बनाया गया है जहां हम एक switch में कोड के एक से अधिक ब्लॉक को हिट करना चाहते हैं, और इसे सामान्य रूप से फॉल-थ्रू को कवर करने के लिए सामान्यीकृत किया गया है। इसने दोनों मामलों को अधिक सुविधाजनक और स्वयं-दस्तावेज भी बनाया है, क्योंकि हमें सी में एक नया लेबल जोड़ना है, लेकिन case को सी # में लेबल के रूप में उपयोग कर सकते हैं। सी # में हम below_six लेबल से छुटकारा पा सकते हैं और goto case 5 उपयोग कर सकते हैं जो कि हम क्या कर रहे हैं के बारे में स्पष्ट है। (हमें default लिए break भी जोड़ना होगा, जिसे मैंने ऊपर दिए गए सी कोड को स्पष्ट रूप से सी # कोड नहीं बनाया है)।

संक्षेप में:

  1. सी # अब 40 साल पहले सी कोड के रूप में सीधे अप्रत्याशित कंपाइलर आउटपुट से संबंधित नहीं है (न ही इन दिनों सी करता है), जो गिरावट के माध्यम से अप्रासंगिक की प्रेरणाओं में से एक बनाता है।
  2. सी # समान भाषाओं से परिचित लोगों द्वारा भाषा की आसान सीखने और आसान पोर्टिंग के लिए, केवल अंतर्निहित break न होने पर सी के साथ संगत रहता है।
  3. सी # बग या गलत समझा कोड का संभावित स्रोत हटा देता है जिसे पिछले चार दशकों से समस्याओं के कारण अच्छी तरह से प्रलेखित किया गया है।
  4. सी # संकलक द्वारा लागू करने योग्य सी (दस्तावेज़ के माध्यम से गिरने) के साथ मौजूदा सर्वोत्तम अभ्यास करता है।
  5. सी # असामान्य मामला बनाता है जिसमें एक अधिक स्पष्ट कोड होता है, सामान्य मामला कोड वाला एक व्यक्ति स्वचालित रूप से लिखता है।
  6. सी # सी में उपयोग किए जाने वाले विभिन्न case लेबल्स से एक ही ब्लॉक को मारने के लिए एक ही goto आधारित दृष्टिकोण का उपयोग करता है। यह कुछ अन्य मामलों में इसे सामान्यीकृत करता है।
  7. सी # जो case स्टेटमेंट्स को लेबल्स के रूप में कार्य करने की इजाजत देकर सी में है, उससे अधिक सुविधाजनक और स्पष्ट दृष्टिकोण बनाता है।

सब कुछ, एक सुंदर उचित डिजाइन निर्णय

* बीएएसआईसी के कुछ रूपों में से किसी को GOTO (x AND 7) * 50 + 240 की पसंद करने की इजाजत मिलेगी, जबकि भंगुर और इसलिए goto पर प्रतिबंध लगाने के लिए विशेष रूप से प्रेरक मामला, एक तरह से उच्च भाषा के समान तरीके से दिखाने के लिए काम करता है कि निम्न-स्तरीय कोड एक मूल्य पर अंकगणित के आधार पर एक कूद बना सकता है, जो कि अधिक उचित है जब संकलन का परिणाम मैन्युअल रूप से बनाए रखा जाना चाहिए। डफ के डिवाइस के कार्यान्वयन विशेष रूप से समकक्ष मशीन कोड या आईएल के लिए खुद को उधार देते हैं क्योंकि निर्देशों का प्रत्येक ब्लॉक अक्सर nop fillers के अतिरिक्त की आवश्यकता के बिना एक ही लंबाई होगी।

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


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

switch(value)
{
    case 1:// this is still legal
    case 2:
}

स्विच (सी # संदर्भ) कहते हैं

सी # को स्विच अनुभागों के अंत की आवश्यकता है, जिसमें अंतिम एक,

तो आपको भी एक break; जोड़ने की जरूरत है break; आपके default खंड में, अन्यथा अभी भी एक कंपाइलर त्रुटि होगी।





switch-statement