2012-10-29 2 views
6

Also, das ist ziemlich einfach, denke ich.Das Ändern des Objekts wirkt sich auf frühere Versionen des Objekts in einer Foreach-Schleife aus

Hier ist mein Code:

Dictionary<int, IEnumerable<SelectListItem>> fileTypeListDict = new Dictionary<int, IEnumerable<SelectListItem>>(); 

foreach (PresentationFile pf in speakerAssignment.FKPresentation.PresentationFiles) 
{ 
    IEnumerable<SelectListItem> fileTypes = Enum.GetValues(typeof(PresentationFileType)) 
       .Cast<PresentationFileType>().Select(x => new SelectListItem 
     { 
      Text = x.ToString(), 
      Value = Convert.ToString((int)x), 
      Selected = pf.Type == (int)x 
     }); 

     fileTypeListDict.Add(pf.ID, fileTypes); 
} 

Was passiert ist, dass das Wörterbuch am Ende alle die richtigen Tasten haben, aber alle Werte werden auf die fileTypes Liste während der letzten Iteration erstellt eingestellt werden der Schleife. Ich bin mir sicher, dass dies etwas mit dem Objekt zu tun hat, das als Referenz verwendet wird, aber ich habe dieses Problem in meiner Zeit mit C# noch nicht gesehen. Wer möchte erklären, warum dies geschieht und wie ich dieses Problem lösen soll?

Danke!

Antwort

9

Dies ist das berüchtigte „foreach Capture-Problem“ und ist „fest“ in C# 5 („fixed“ ist ein starkes Wort, denn es schlägt es ein „Fehler“ war vor: in der Realität - die Spezifikation jetzt geändert wird dies als eine allgemeine Ursache der Verwirrung anzuerkennen). In beiden Fällen nimmt das Lambda den variablepf, nicht "den Wert von pf während dieser Iteration" - aber in C# vor-5 die Variable pf ist technisch die Schleife außerhalb scoped (so gibt es nur einer davon, Punkt), wo - wie in C# 5 und oberhalb der Variablen innerhalb die Schleife (so gibt es eine andere Variable, für Erfassungszwecke, pro Iteration).

In C# 4, betrügen nur:

foreach (PresentationFile tmp in speakerAssignment.FKPresentation.PresentationFiles) 
{ 
    PresentationFile pf = tmp; 
    //... as before 

jetzt pf innerhalb des foreach scoped ist, und es wird OK arbeiten. Ohne diese gibt es nur einen pf - und da Sie die Ausführung bis zum Ende aufgeschoben haben, wird der Wert der einzelnen pf die letzte Iteration sein.

Eine Alternative fix wäre: Sie verschieben die Ausführung nicht:

fileTypeListDict.Add(pf.ID, fileTypes.ToList()); // note the ToList 

Nun wird ausgewertet während der pf „aktuellen“ ist, so wird die Ergebnisse haben Sie erwartet.

+0

Ich schätze die schnelle und gründliche Erklärung. Ich wünsche ihnen einen wunderbaren Tag! – PFranchise