2011-01-13 9 views
37

मैं नए कार्यों के साथ खेलने का पहला प्रयास कर रहा हूं, लेकिन कुछ ऐसा हो रहा है जिसे मैं समझ नहीं पा रहा हूं।फोरच में कार्य शुरू करना लूप का उपयोग अंतिम आइटम का मूल्य

सबसे पहले, कोड, जो कि सीधे सीधा है। मैं कुछ छवि फ़ाइलों के लिए पथ की एक सूची में गुजरती हैं, और उनमें से प्रत्येक पर कार्रवाई करने के कार्य जोड़ने के लिए प्रयास:

public Boolean AddPictures(IList<string> paths) 
{ 
    Boolean result = (paths.Count > 0); 
    List<Task> tasks = new List<Task>(paths.Count); 

    foreach (string path in paths) 
    { 
     var task = Task.Factory.StartNew(() => 
      { 
       Boolean taskResult = ProcessPicture(path); 
       return taskResult; 
      }); 
     task.ContinueWith(t => result &= t.Result); 
     tasks.Add(task); 
    } 

    Task.WaitAll(tasks.ToArray()); 

    return result; 
} 

मैंने पाया है, तो मैं बस के साथ, कहते हैं यह रन, 3 की एक सूची है कि यूनिट परीक्षण में पथ, सभी तीन कार्य प्रदान की गई सूची में अंतिम पथ का उपयोग करते हैं। यदि मैं (और लूप की प्रसंस्करण को धीमा कर देता हूं) के माध्यम से कदम उठाता हूं, तो लूप से प्रत्येक पथ का उपयोग किया जाता है।

क्या कोई यह बता सकता है कि क्या हो रहा है, और क्यों? संभावित कामकाज?

+3

मैं ReSharper उपयोग करने का सुझाव मई पकड़ता यह विशेष रूप से त्रुटि और अन्य संभावित कीड़े आप –

उत्तर

73

आप पाश चर के ऊपर बंद करने जा रहे हैं। ऐसा मत करो। इसके बारे में नहीं मूल्य आप कार्य बनाने जब, लेकिन चर ही -

foreach (string path in paths) 
{ 
    string pathCopy = path; 
    var task = Task.Factory.StartNew(() => 
     { 
      Boolean taskResult = ProcessPicture(pathCopy); 
      return taskResult; 
     }); 
    task.ContinueWith(t => result &= t.Result); 
    tasks.Add(task); 
} 

आपके मौजूदा कोड path कैप्चर कर रहा है: के बजाय एक प्रति ले लो। प्रत्येक बार जब आप लूप के माध्यम से जाते हैं तो वह चर बदलता है - इसलिए जब आपके प्रतिनिधि को बुलाया जाता है तो यह आसानी से बदल सकता है।

चर की एक प्रति लेने से, आप एक नई चर हर बार जब आप पाश के माध्यम से जाना शुरू कर रहे हैं - जब आप कि चर पर कब्जा, यह पाश की अगले चरण में परिवर्तित नहीं किया जाएगा ।

एरिक लिपर्ट में ब्लॉग पोस्ट की एक जोड़ी है जो इसमें बहुत अधिक विस्तार से जाती है: part 1; part 2

बुरा लग रहा है नहीं -।। यह लगभग हर कोई बाहर :(

+1

लेकिन पेड़ और सब के लिए पाठ्यक्रम वन के लिए highlighten कर रहे हैं। :) –

+1

यह बंद करने की समस्या और रैंडम() का उचित उपयोग SO – BrokenGlass

+0

पर शीर्ष 5 आवृत्ति-वार में होना चाहिए कृपया ध्यान दें कि यह "बग" (जो मूल रूप से * डिज़ाइन * था) को सी में तय किया जाना चाहिए # 5.0 –

12

लैम्ब्डा है कि आप StartNew को गुजर रहे path चर, जो प्रत्येक यात्रा पर परिवर्तन संदर्भित कर रहा है (अर्थात अपने लैम्ब्डा संदर्भ path की के बजाय सिर्फ अपने मूल्य का इस्तेमाल कर रही है)। ताकि आप एक संस्करण है कि बदल जाएगा की ओर इशारा करते नहीं कर रहे हैं आप इसे की स्थानीय प्रतिलिपि बना सकते हैं:

foreach (string path in paths) 
{ 
    var lambdaPath = path; 
    var task = Task.Factory.StartNew(() => 
     { 
      Boolean taskResult = ProcessPicture(lambdaPath); 
      return taskResult; 
     }); 
    task.ContinueWith(t => result &= t.Result); 
    tasks.Add(task); 
} 
संबंधित मुद्दे