2013-03-08 5 views
6
अंदर गुण सेट करने में नाकाम रहने #

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

IEnumberable<myObject> objects = GetObjectsFromApiCall(); 

    for (int i = 0; i < objects.Count(); i++) 
     { 
      if (String.IsNullOrEmpty(objects.ElementAt(i).SubObject.Title)) 
      { 
       SubObject sub = GetSubObjectFromDatabase((long)objects.ElementAt(i).SubObject.Id); 
       if (sub != null) 
       { 
        objects.ElementAt(i).SubObject.Title = sub.Title; 
       } 
      } 
     } 

जब आप इसके माध्यम से कदम, इस कोड के बारे में सब कुछ ठीक से काम करने लगता है:

कोड का एक खंड है कि इस तरह दिखता है मिल गया। "ऑब्जेक्ट्स" संग्रह अपेक्षित के रूप में आबादी है। "उप" एकत्रित के रूप में लाया जाता है और एक आबादी वाले शीर्षक संपत्ति सहित अपेक्षित गुणों का पूरा सेट होता है। निष्पादन के दौरान कोई त्रुटि नहीं फेंक दी जाती है।

लेकिन ... SubObject.Title संपत्ति (जो सिर्फ मानक प्राप्त है; सेट; कोड) मौजूद है कि प्रत्येक वस्तु में हठ खाली रहता है।

मुझे नुकसान हुआ है। कोई भी बता रहा है कि क्या हो रहा है?

संपादित करें: जिन लोगों ने सुझाव दिया है कि मुझे लूप और एलिमेंट एट के लिए उपयोग नहीं करना चाहिए, मैंने एक फोरैच लूप के साथ शुरुआत की लेकिन सोचा कि यह समस्या का स्रोत हो सकता है क्योंकि यह हर बार एक नया सबऑब्जेक्ट ला रहा था। अब आपकी मदद के लिए धन्यवाद, और ForEach बहाल।

चीयर्स, मैट

+4

वहां आप जाते हैं: [IENumerable के भीतर कोई आइटम प्रॉपर्टी अपडेट करना लेकिन संपत्ति सेट नहीं रहती है?] (Http://stackoverflow.com/a/9104212/93732) –

+0

इस कोड में इतनी धीमी गति होने की संभावना है मजाकिया भी नहीं है। – ChaosPandion

+0

क्या आप * वास्तविक * कोड की प्रतिलिपि/पेस्ट कर सकते हैं, ऐसा नहीं * * * * * वास्तविक * कोड की तरह दिखता है? – ken2k

उत्तर

4

मैं इसे इस तरह से तय होगा:

var objects = GetObjectsFromApiCall().ToList(); 

तो फिर तुम पाश रख सकता है के रूप में (यह काम करता है), या के रूप में अन्य उत्तर ने सुझाव दिया है कि यह एक foreach और कुछ LINQ का उपयोग कर बिट का अनुकूलन, लेकिन यह करता है वास्तव में कोई फर्क नहीं पड़ता: समस्या यह थी कि आपने IENumerator <> पर एक तत्व बदलने का प्रयास किया जैसा कि this question में बताया गया है @Ahmet Kakıcı द्वारा इंगित किया गया।

public IEnumberable<myObject> GetObjectsFromApiCall(){ 
    for(var i = 0; i < 10; i++) 
    { 
     yield return new myObject(); 
    } 
} 

अगर मैं सही हूँ, हर बार जब आप फोन objects.ElementAt (i) समारोह वस्तु प्राप्त करने के लिए:

+1

-1 यह वास्तव में गलत है। 'IENumerable' द्वारा लौटाए गए तत्वों को संशोधित करने में कोई समस्या नहीं है। असल में, जब आप 'toList()' के बाद 'foreach' का उपयोग कर रहे हैं, तो आप' IENumerable' का उपयोग कर रहे हैं, 'सूची ' लागू करें 'IENumerable '। एक समस्या एक डीबी क्वेरी के * स्थगित निष्पादन * हो सकती है, लेकिन यह निश्चित रूप से 'IENumerable' इंटरफेस की सरल उपस्थिति के कारण नहीं है ... – ken2k

+0

आप सही हैं, मैंने बहुत तेज़ पढ़ा है ... समस्या आईनेमरेबल नहीं है लेकिन जिस तरह से इसे लागू किया गया है। यही कारण है कि ToList() का उपयोग समझ में आता है। स्पष्टीकरण के लिए धन्यवाद। – Larry

+0

@ केन 2 के सही। उन उदाहरणों के लिए मेरा उत्तर देखें जहां मैं 'IENumerable' द्वारा लौटाई गई वस्तुओं को संशोधित करता हूं। –

1

सबसे पहले, आप कोड के इस प्रकार के लिए ElementAt() उपयोग नहीं करना चाहिए, का उपयोग

foreach (var o in objects) 
{ 
    if (string.IsNullOrEmpty(o.SubObject.Title)) 
    { 
     o.SubObject.Title = ...; 
    } 
} 
इसके अलावा, आप को ध्यान देना चाहिए

कि आपके विधि हर बार एक गतिशील IEnumerable वापस लौट आता है तो आप कॉल objects.Something() एपीआई फिर कहा जाता है और ताज़ा प्रति लिया गया है। यदि यह मामला है, तो आप .ToList() विधि का उपयोग कर एक सूची में गणनीय कॉपी चाहिए। इस तरह एक गतिशील प्रगणक बनाने के द्वारा -

भी नहीं सूची में एक प्रति डालने का एक तरीका नहीं है:

objects = objects.Select(o => 
{ 
    if (string.IsNullOrEmpty(o.SubObject.Title)) 
    { 
     o.SubObject.Title = ...; 
    } 
    return o; 
}); 

सही ढंग से नहीं स्थापित किया जा रहा है (अगर पिछले बातें मदद नहीं की) मूल्य के लिए के रूप में - Title संपत्ति के लिए सेटर में एक throw new Exception(value) जोड़ने का प्रयास करें - यह है कि अगर सही मान के साथ बुलाया जा रहा है देखते हैं।

+0

"सबसे पहले, आपको इस तरह के कोड के लिए ElementAt() का उपयोग नहीं करना चाहिए।" क्यूं कर? –

+0

.NET मूल्य प्राप्त करने के लिए 'i' बार के लिए' Enumerator.MoveNext() 'का उपयोग करके हर बार गणना करेगा। यह 'सूची [i] 'दृष्टिकोण से धीमा तरीका है। –

2

इस

List<myObject> objects = GetObjectsFromApiCall().ToList(); 

foreach(var obj in objects.Where(o => string.IsNullOrEmpty(objects.SubObject.Title)).ToList()) 
{ 
    var subObject = GetSubObjectFromDatabase(obj.SubObject.Id); 
    if(subObject == null) continue; 

    obj.SubObject.Title = subObject.Title; 
} 
1

मैं अतिथि समारोह GetObjectsFromApiCall ऐसा दिखाई देता है की कोशिश करो , तो आप "yield return new myObject()" द्वारा एक नई वस्तु मिल जाएगा।

+0

यह एक अच्छा सिद्धांत है। मैं इस तरह एक उदाहरण पोस्ट करने की सोच रहा था। –

+0

ओह, आपको "ऑब्जेक्ट्स बदलना चाहिए। एलिमेंट एट (i) .SubObject.Title = sub.Title;" "var obj = object.ElementAt (i) .SubObject; obj.Title = sub.Title;" – fengyj

+0

आपकी टिप्पणी के बारे में: यह क्या बदलेगा? –

1

लेकिन आप कैसे जांचते हैं कि Title संपत्ति बदल दी गई है? क्या आप GetObjectsFromApiCall() फिर से कॉल करते हैं? या आप foreach उसी objects उदाहरण के माध्यम से फिर से करते हैं?

एक IEnumerable उदाहरण प्रत्येक बार "गणना" होने पर नई वस्तुओं को बना और उत्पन्न कर सकता है। तो यहां चित्रण के लिए एक सरल उदाहरण है। उदाहरण के लिए, निर्धारित करें:

static IEnumerable<SomeObject> GetSomeSequence() 
    { 
     yield return new SomeObject { Title = "Alpha", }; 
     yield return new SomeObject { Title = "Beta", }; 
     yield return new SomeObject { Title = "Gamma", }; 
    } 

तो यह इस तरह का परीक्षण:

class SomeObject 
{ 
    public string Title { get; set; } 
} 

तब हमने "स्रोत" के दो प्रकार, पहले एक सरणी, और फिर एक iterator ब्लॉक इस तरह परिभाषित विचार करेंगे:

static void Main() 
    { 
     IEnumerable<SomeObject> thingsToModify; 

     // set source to an array 
     thingsToModify = new[] { new SomeObject { Title = "Alpha", }, new SomeObject { Title = "Beta", }, new SomeObject { Title = "Gamma", }, }; 

     foreach (var t in thingsToModify) 
      Console.WriteLine(t.Title); 

     foreach (var t in thingsToModify) 
      t.Title = "Changed!"; 

     foreach (var t in thingsToModify) 
      Console.WriteLine(t.Title); // OK, modified 


     // set source to something which yields new object each time a new GetEnumerator() call is made 
     thingsToModify = GetSomeSequence(); 

     foreach (var t in thingsToModify) 
      Console.WriteLine(t.Title); 

     foreach (var t in thingsToModify) 
      t.Title = "Changed!";   // no-one keeps these modified objects 

     foreach (var t in thingsToModify) 
      Console.WriteLine(t.Title); // new objects, titles not modified 

    } 

निष्कर्ष: यह एक परिवर्तनशील वस्तु जो स्रोत हम से अधिक पुनरावृत्ति कर रहे हैं के अंतर्गत आता है की स्थिति संशोधित करने के लिए पूरी तरह से संभव है। लेकिन कुछ प्रकार के IEnumerable स्रोत प्रत्येक बार डेटा की नई प्रतियां उत्पन्न करते हैं, और फिर प्रतिलिपि में संशोधन करने के लिए बेकार है।