2012-02-13 35 views
6

के अंदर मैन्युअल रूप से एक गणनाकर्ता को बढ़ाएं मेरे पास एक फोरैच लूप के अंदर लूप है जबकि मैं निश्चित स्थिति को पूरा करते समय अनिश्चितता से आगे बढ़ाना चाहता हूं। ऐसा करने के लिए मैं एन्यूमेरेटर < टी> (जो कि यह फ़ोरैच लूप में होना चाहिए) के लिए गणनाकर्ता को कास्ट करने का प्रयास करें, फिर जाली ऑब्जेक्ट पर MoveNext() को कॉल करना, लेकिन यह मुझे एक त्रुटि देता है कि मैं इसे परिवर्तित नहीं कर सकता।फोरैच लूप

सिस्टम 'डेटा.डेटाइम' को सिस्टम में परिवर्तित नहीं कर सकता। चयन। जेनरिक.इंटर्यूमेरेटर संदर्भ संदर्भ, मुक्केबाजी रूपांतरण, अनबॉक्सिंग रूपांतरण, रैपिंग रूपांतरण, या शून्य प्रकार रूपांतरण के माध्यम से।

 foreach (DateTime time in times) 
     { 
      while (condition) 
      { 
       // perform action 
       // move to next item 
       (time as IEnumerator<DateTime>).MoveNext(); // will not let me do this 
      } 

      // code to execute after while condition is met 
     } 

सबसे अच्छा तरीका मैन्युअल foreach लूप के अंदर IEnumerator बढ़ाने के लिए क्या है?

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

+0

जवाब के अलावा, एक बात आप याद आ रही हो सकता है: 'time' एक' DateTime' है, जो लागू नहीं करता है 'IEnumerator' –

+0

कैसे foreach पाश अग्रिम यह अगर इसे लागू नहीं करता है सकते हैं आईएन्यूमेरेटर इंटरफ़ेस? – Despertar

+1

अपना कोड देखें। 'foreach (समय में दिनांक समय)'। ऑब्जेक्ट की गणना की जा रही है। –

उत्तर

12

अन्य उत्तर से कई continue है, जो बहुत अच्छी तरह से मदद मिल सकती है क्या आप सब करने की ज़रूरत क्या कर का उपयोग करें। हालांकि, मैन्युफैक्चरर को मैन्युअल रूप से स्थानांतरित करने के हित में, सबसे पहले आपको में अंकुश होना चाहिए, और इसका मतलब है कि while के रूप में अपना लूप लिखना।

using (var enumerator = times.GetEnumerator()) 
{ 
    DateTime time; 
    while (enumerator.MoveNext()) 
    { 
     time = enumerator.Current; 
     // pre-condition code 
     while (condition) 
     { 
      if (enumerator.MoveNext()) 
      { 
       time = enumerator.Current; 
       // condition code 
      } 
      else 
      { 
       condition = false; 
      } 
     } 
     // post-condition code 
    } 
} 

अपनी टिप्पणी से:

कैसे foreach पाश अग्रिम यह IEnumerator इंटरफ़ेस को लागू नहीं करता है तो कर सकते हैं?

आपके लूप में, time एक DateTime है। यह वह ऑब्जेक्ट नहीं है जिसे लूप में काम करने के लिए इंटरफेस या पैटर्न को कार्यान्वित करने की आवश्यकता है। timesDateTime मानों का एक अनुक्रम है, यह वह है जो गणनात्मक पैटर्न को लागू करना होगा। यह आमतौर पर IEnumerable<T> और IEnumerable इंटरफेस को कार्यान्वित करके पूरा किया जाता है, जिसे केवल T GetEnumerator() और object GetEnumerator() विधियों की आवश्यकता होती है। विधियां IEnumerator<T> और IEnumerator को कार्यान्वित करने वाली ऑब्जेक्ट को वापस करती हैं, जो bool MoveNext() विधि और T या object Current संपत्ति को परिभाषित करती है। लेकिन time को IEnumerator पर नहीं डाला जा सकता है, क्योंकि यह ऐसी कोई बात नहीं है, और न ही times अनुक्रम है।

+0

उत्कृष्ट स्पष्टीकरण के लिए धन्यवाद! यह मेरे प्रश्न का उत्तर देता है कि गणक को मैन्युअल रूप से कैसे बढ़ाया जाए और यह बताता है कि मेरा कास्टिंग क्यों काम नहीं करता है। मुझे लगता है कि समय गणनाकर्ता था, लेकिन समय वास्तव में केवल वेरिएबल है जो गणनाकर्ताओं का मूल्य रखता है वर्तमान संपत्ति (अगर मैं गलत हूं तो मुझे सही करें)। यह भी बताता है कि क्यों कस्टम क्लास जो आईन्यूमेरेटर कंटेनरों के अंदर आईन्यूमेरेटर काम से विरासत में नहीं आतीं। – Despertar

+1

पुनरावृत्ति के अंत में गैर-समाप्ति के दौरान देखें (स्थिति) –

+0

@ डेविड, हाँ, अच्छा बिंदु। –

5

आप लूप के अंदर से गणनाकर्ता को संशोधित नहीं कर सकते हैं। भाषा इस पर अनुमति नहीं देती है। लूप के अगले पुनरावृत्ति पर अग्रिम करने के लिए आपको जारी कथन का उपयोग करने की आवश्यकता है।

हालांकि, मुझे विश्वास नहीं है कि आपके लूप को भी जारी रखने की आवश्यकता है। पढ़ते रहिये।

अपने कोड के संदर्भ में आपको फोरैच ब्लॉक को जारी रखने के लिए थोड़ी देर में कनवर्ट करना होगा।

foreach (DateTime time in times)  
{  
    if (condition) 
    { 
      // perform action 
      continue; 
    } 
    // code to execute if condition is not met  
} 

लेकिन इस तरह लिखा यह स्पष्ट है कि निम्नलिखित बराबर संस्करण सरल है अभी भी

foreach (DateTime time in times)  
{  
    if (condition) 
    { 
      // perform action 
    } 
    else 
    { 
      // code to execute if condition is not met 
    } 
} 

इसका कारण यह है भाग के बाद निष्पादित करने के लिए कोड में चिह्नित है, जबकि स्थिति उत्पन्न होने पर अपने छद्म कोड के बराबर है प्रत्येक आइटम के लिए निष्पादित किया गया है जिसके लिए स्थिति गलत है।

मेरी सभी धारणा यह है कि सूची में प्रत्येक आइटम के लिए स्थिति का मूल्यांकन किया जाता है।

+0

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

+0

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

+0

मैं देखता हूं कि अब आपका क्या मतलब है, यह काम करेगा। आपके इनपुट के लिए धन्यवाद। – Despertar

3

शायद आप continue का उपयोग कर सकते हैं?

+2

यह खतरे में नहीं है। उत्तर किसी प्रश्न के रूप में phrased करने की आवश्यकता नहीं है। आत्मविश्वास रखो! –

3

आप बयान जारी रखने के लिए प्रयोग करेंगे: continue;

0

आप अपने इटरेटर के रूप में एक func का उपयोग कर सकते हैं और उस राज्य को बदल सकते हैं जिसे आप प्रत्येक प्रतिनिधिमंडल का मूल्यांकन करने के लिए उस प्रतिनिधि में बदल रहे हैं।

public static IEnumerable<T> FunkyIEnumerable<T>(this Func<Tuple<bool, T>> nextOrNot) 
    { 
     while(true) 
     { 
      var result = nextOrNot(); 

      if(result.Item1) 
       yield return result.Item2; 

      else 
       break; 

     } 

     yield break; 

    } 

    Func<Tuple<bool, int>> nextNumber =() => 
      Tuple.Create(SomeRemoteService.CanIContinueToSendNumbers(), 1); 

    foreach(var justGonnaBeOne in nextNumber.FunkyIEnumerable()) 
      Console.Writeline(justGonnaBeOne.ToString()); 
+0

अपने कोड स्वरूपण (थोड़ा) फिक्स्ड। –

+0

चीयर्स। यह भयानक था ... – OskarK

1

यह सिर्फ एक अनुमान है, लेकिन यह है कि आप क्या करने की कोशिश कर रहे हैं datetimes की एक सूची लेने के लिए और ले जाने के अतीत उन सभी को जो एक कुछ मानदंडों को पूरा है, तो के बाकी पर कोई कार्रवाई करने की तरह लगता है सूचि। यदि आप यही करने की कोशिश कर रहे हैं, तो शायद आप System.Linq से SkipWhile() जैसे कुछ चाहते हैं। उदाहरण के लिए, निम्नलिखित कोड डेटाटाइम की एक श्रृंखला लेता है और उन सभी के पीछे छोड़ देता है जो कटऑफ तिथि से पहले हैं; तो यह शेष डेटाटाइम प्रिंट करता है:

var times = new List<DateTime>() 
    { 
     DateTime.Now.AddDays(1), DateTime.Now.AddDays(2), DateTime.Now.AddDays(3), DateTime.Now.AddDays(4) 
    }; 

var cutoff = DateTime.Now.AddDays(2); 

var timesAfterCutoff = times.SkipWhile(datetime => datetime.CompareTo(cutoff) < 1) 
    .Select(datetime => datetime); 

foreach (var dateTime in timesAfterCutoff) 
{ 
    Console.WriteLine(dateTime); 
} 

Console.ReadLine(); 

क्या आप जिस तरह की चीज करने की कोशिश कर रहे हैं?

+0

वैसे मैं उन शर्तों को छोड़ना नहीं चाहता था जो इस शर्त से मिले थे, मैं उन्हें एक उप-सूची में जमा करना चाहता था जिसे थोड़ी देर बाद संसाधित किया जाएगा। हालांकि आपके LINQ संदर्भ ने मुझे LINQ को एक और शॉट देने के लिए प्रोत्साहित किया (जो मैंने मूल रूप से उपयोग किया था) और इसने मेरी समस्या को एक बहुत ही सरल तरीके से हल किया (जैसा कि LINQ आमतौर पर करता है)। धन्यवाद। – Despertar

0

एक विकल्प का अभी तक उल्लेख नहीं किया गया है कि एक गणक एक रैपर ऑब्जेक्ट लौटाए जो डेटा तत्व को समझाए जाने के अलावा स्वयं तक पहुंच की अनुमति देता है। नमूने के लिए:

 
struct ControllableEnumeratorItem<T> 
{ 
    private ControllableEnumerator parent; 
    public T Value {get {return parent.Value;}} 
    public bool MoveNext() {return parent.MoveNext();} 
    public ControllableEnumeratorItem(ControllableEnumerator newParent) 
    {parent = newParent;} 
} 

यह दृष्टिकोण भी डाटा संरचनाओं कि संग्रह गणन के दौरान नियंत्रित फैशन में संशोधित करने की अनुमति देना चाहते हैं के द्वारा प्रयोग किया जा सकता है ("DeleteCurrentItem", "AddBeforeCurrentItem" शामिल करके जैसे, और "AddAfterCurrentItem" विधि) ।

1

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

public static void Main(string[] args) 
{ 
    IEnumerable<DateTime> times = GetTimes(); 
    foreach (var step in times.StepWise()) 
    { 
    while (condition) 
    { 
     step.MoveNext(); 
    } 
    Console.WriteLine(step.Current); 
    } 
} 

फिर हमें हमारी StepWise एक्सटेंशन विधि बनाने की आवश्यकता है।

public static class EnumerableExtension 
{ 
    public static IEnumerable<Step<T>> StepWise<T>(this IEnumerable<T> instance) 
    { 
     using (IEnumerator<T> enumerator = instance.GetEnumerator()) 
     { 
      while (enumerator.MoveNext()) 
      { 
       yield return new Step<T>(enumerator); 
      } 
     } 
    } 

    public struct Step<T> 
    { 
     private IEnumerator<T> enumerator; 

     public Step(IEnumerator<T> enumerator) 
     { 
      this.enumerator = enumerator; 
     } 

     public bool MoveNext() 
     { 
      return enumerator.MoveNext(); 
     } 

     public T Current 
     { 
      get { return enumerator.Current; } 
     } 

    } 
}