2011-05-05 13 views
11

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

यदि किसी शर्त का पता चला है तो मैं वर्तमान विधि से कैसे टूट सकता हूं और मैं अगले संपर्क पर जाना चाहता हूं? मैं मुख्य फोरेच लूप से कुछ स्तरों में एक विधि में हूं।

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

तो, मैं क्या करूँ?

+0

क्या आप कोड नमूना प्रदान कर सकते हैं? –

उत्तर

3

आप शायद एक झंडा हो सकता था ... bool conditionDetected और जब एक शर्त का पता चला है तो आप सिर्फ सही करने के लिए यह सेट और जब तक आप शीर्ष करने के लिए मिलता तरीकों से if (conditionDetected) return; है की तरह कुछ है जहाँ आप अगले एक करने के लिए if(conditionDetected) continue .. । फिर आप इसे फिर से झूठ बोलते हैं और आगे बढ़ते हैं ... आपको एक त्रुटि मिलती है क्योंकि जब आप किसी अन्य विधि पर जाते हैं तो आप फोरैच लूप के अंदर नहीं होते हैं

1

एक समाधान एक कस्टम अपवाद फेंकना होगा जो अंततः आपके foreach लूप द्वारा पकड़ा जाएगा।

सुनिश्चित करें कि आप एक कस्टम अपवाद का उपयोग कर रहे हैं (यानी इसका अपना प्रकार है और न केवल catch(Exception) कथन का उपयोग करके), इस तरह आप जानते हैं कि आप निश्चित रूप से सही को पकड़ रहे हैं।

catch ब्लॉक में, बस अपने फ़ोरैच लूप (या उचित तरीके से संभाल लें) के साथ जारी रखें।

try { 
    MethodWithIteration(i); 
} catch (ProcessingFailedException) { 
    continue; 
} 

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


foreach(DoSomethingWithMe doSomething in objList) 
{ 
    // Option 1 : Custom Processing Exception 
    try 
    { 
     ProcessWithException(doSomething); 
    } catch(ProcessingFailedException) 
    { 
     // Handle appropriately and continue 
     // .. do something .. 
     continue; 
    } 

    // Option 2 : Check return value of processing 
    if (!ProcessWithBool(doSomething)) 
     continue; 

    // Option 3 : Simply continue on like nothing happened 
    // This only works if your function is the only one called (may not work with deeply-nested methods) 
    ProcessWithReturn(doSomething); 
} 
+15

Ewwww ... प्रवाह नियंत्रण के लिए अपवाद yucky –

+0

मैंने अर्ध-अस्वीकरण जोड़ा ;-) –

6

आपका समर्थन तरीकों शायद एक मूल्य के जो मुख्य विधि के लिए लूप में चेक किया गया है, और फिर वहाँ है कि क्या मान को इंगित करता है से continue लौटना चाहिए।

अपवादों का उपयोग करना एक और विकल्प है, लेकिन उन्हें आम तौर पर धीमा माना जाता है - मुझे विशेष रूप से सी # के बारे में निश्चित नहीं है। इस तरह प्रयोग किए जाने पर उन्हें आमतौर पर खराब रूप माना जाता है। अपवादों को असाधारण स्थितियों में फेंक दिया जाना चाहिए, प्रवाह नियंत्रण के सामान्य हिस्से के रूप में नहीं। तर्कसंगत स्थितियां हैं जहां इन तरीकों से उनका उपयोग करना ठीक है, जैसे कि वेब फ्रेमवर्क प्ले !, लेकिन आप शायद उनमें से एक में नहीं हैं।

+1

यह मोनाड शैली प्रवाह नियंत्रण है ;-) – BrokenGlass

0

जारी रखने के लिए आपको सीधे लूप के अंदर होना चाहिए, इसलिए आप लूप में ब्रेक के बारे में जागरूक होने की आवश्यकता है, लेकिन क्या आप बस तरीकों से एक बूल वापस नहीं कर सकते?

int[] ints = {1,2,3,4,5,6}; 

foreach (var k in ints) 
{ 
    if (Continue(k)) 
    { 
     continue; 
    } 
} 


bool Continue(int k) 
{ 
    return what's suitable 
} 
2

इसे पूरा करने का कोई आसान तरीका नहीं है। एकमात्र ऐसा स्थान जहां आप foreach लूप के अगले पुनरावृत्ति को मजबूर कर सकते हैं, सीधे उसके शरीर के भीतर से है। इसलिए ऐसा करने के लिए आपको foreach लूप के शरीर में विधि से बाहर जाना चाहिए।

को प्राप्त करने के तरीके के एक जोड़े इस

  • एक अपवाद फेंक रहे हैं: कृपया, कृपया ऐसा नहीं करते हैं। अपवाद एक नियंत्रण प्रवाह तंत्र
  • बाहर निकलें विधि के रूप में नहीं किया जाना चाहिए, और तुम और एक वापसी कोड शरीर एक continue बयान
2

अगर मैं कर रहा हूँ पर अमल करने का कारण बनता है कि साथ foreach पाश के बीच सभी तरीकों सही तरीके से अपने समस्या को समझने, तुम इतनी तरह पाश के लिए एक है:

for(int i = 0; i < 100; i++) 
{ 
    DoComplexProcessing(); 
} 

DoComplexProcessing तो एक और तरीका है, जो किसी अन्य विधि और इतने पर कॉल कहते हैं।

एक बार जब आप नीचे आते हैं, तो कहें, 4 स्तर, आप एक शर्त (जो भी हो) का पता लगाते हैं और अपने DoComplexProcessing के पुनरावृत्ति को रोकना चाहते हैं।

यह मानना ​​सही है कि मैं क्या करूँगा, एक ऐसी वस्तु है जो विधि श्रृंखला के साथ out पैरामीटर के रूप में सवारी करती है, प्रत्येक स्तर पर, "खराब" स्थिति मिलने के बाद, मैं शून्य (या कुछ अन्य डिफ़ॉल्ट मान वापस कर दूंगा) जब शून्य एक विकल्प नहीं है) और संदर्भ वस्तु को उस स्थिति में सेट करें जिसका अर्थ है 'निरस्त करें।' प्रत्येक विधि तब उस 'निरस्त' स्थिति की जांच करेगी और फिर वही करेगी "वापसी नल, ऑब्जेक्ट को 'abort' पर कॉल करें।

कुछ इस तरह:

TracerObject tracer = new tracer("good"); 
for(int i = 0; i < 100; i++) 
{ 
    DoComplexProcessing(out tracer) 
    if(tracer.status == "abort") DoSomethingElse() 
} 

अगली विधि इस

DoComplexProcessing(out TracerObject tracer) 
{ 
    var myObject = new MyObject() 
    myObject.Property = DoSlightlyLessComplexProcessing(myObject, out tracer) 
    if(tracer.Status == "abort") 
    { 
    //set myObject.Property to some default value 
    } 
    return myObject; 
} 
} 
20

आप यहाँ नीचे जा रहे हैं एक बुरा पथ कर सकता; एक कदम वापस ले लो और अपने डिजाइन पर पुनर्विचार करें।

सामान्यतः यह उन तरीकों का एक बहुत बुरा विचार है जो उनके कॉलर्स के नियंत्रण प्रवाह को प्रभावित करने का प्रयास करते हैं। एक विधि कॉलर का नौकर है, मास्टर नहीं। विधि यह तय नहीं करती है कि कॉलर आगे क्या करता है; यह उसका व्यवसाय नहीं है। बल्कि, एक विधि:

  • एक गणना करता है और एक परिणाम देता है, या
  • कुछ राज्य संशोधित करता है और
  • एक अपवाद फेंकता है तो आपरेशन वहाँ सफलतापूर्वक

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

1

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

उदाहरण के लिए मान लीजिए कि आप "छोड़" और "रद्द" बटन है कि उपयोगकर्ता या तो एक अनुबंध को छोड़, या पूरी तरह से प्रसंस्करण रद्द करते है - आप एक छोटे से इस तरह अपने कोड strucutre सकता है:

foreach (var contact in contacts) 
{ 
    if (Cancel) 
    { 
     return; 
    } 
    ContactProcessor processor = new ContactProcessor(contact); 
    processor.Process(contact); 
} 

class ContactProcessor 
{ 
    public bool Skip { get; set; } 

    private readonly Contact contact; 
    public ContactProcessor(Contact contact) 
    { 
     this.contact = contact; 
    } 

    public void Process() 
    { 
     if (!this.Skip) 
     { 
      FooSomething(); 
     } 
     if (!this.Skip) 
     { 
      BarSomething(); 
     } 
     // Etc... 
    } 

    publiv void BarSomething() 
    { 
     // Stuff goes here 
     if (this.contact.WTF()) 
     { 
      this.Skip = true; 
     } 
    } 
} 

(वहाँ स्पष्ट रूप से यहां बहुत से मांसपेशियों को बाहर किया जा रहा है)

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

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

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