2014-06-10 7 views
5

Der Titel deutet darauf hin, dass ich schon eine Idee habe, was vor sich geht, aber ich kann es nicht erklären. Ich habe versucht, eine List<string[]> dynamisch von jeder "Spalte" zu bestellen, beginnend mit dem ersten und endend mit dem Minimum Length aller Arrays.For-Loop und die verzögerte Ausführung von LINQ spielen nicht gut zusammen

Also in diesem Beispiel ist es 2, weil die letzte string[] nur zwei Elemente:

List<string[]> someValues = new List<string[]>(); 
someValues.Add(new[] { "c", "3", "b" }); 
someValues.Add(new[] { "a", "1", "d" }); 
someValues.Add(new[] { "d", "4", "a" }); 
someValues.Add(new[] { "b", "2" }); 

Jetzt habe ich versucht, alle von der ersten und der zweiten Säule zu bestellen. Ich kann es auf diese Weise statisch tun könnte:

someValues = someValues 
    .OrderBy(t => t[0]) 
    .ThenBy(t => t[1]) 
    .ToList(); 

Aber wenn ich weiß nicht, die Zahl der „Spalten“ i diese Schleife verwenden könnte (das ist, was ich dachte):

int minDim = someValues.Min(t => t.GetLength(0)); // 2 
IOrderedEnumerable<string[]> orderedValues = someValues.OrderBy(t => t[0]); 
for (int i = 1; i < minDim; i++) 
{ 
    orderedValues = orderedValues.ThenBy(t => t[i]); 
} 
someValues = orderedValues.ToList(); // IndexOutOfRangeException 

Aber die funktioniert nicht, es schlägt mit einem IndexOutOfRangeException in der letzten Zeile fehl. Der Debugger sagt mir, dass i zu dieser Zeit 2 ist, so dass die for-Schleife-Bedingung ignoriert wird, i ist bereits == minDim.

Warum ist das so? Was ist der richtige Weg dafür?

Antwort

7

Es ist das gleiche Problem wie viele Leute mit foreach hatte pre C-Schleifen # 5.

orderedValues = orderedValues.ThenBy(t => t[i]); 

Der Wert i wird nicht ausgewertet, bis Sie .ToList() aufrufen, an diesem Punkt ist es 2, da dies die Ausgangsbedingung der for-Schleife ist.

Sie können eine neue lokale Variable in der for-Schleife einzuführen, es zu beheben:

for (int i = 1; i < minDim; i++) 
{ 
    var tmp = i; 
    orderedValues = orderedValues.ThenBy(t => t[tmp]); 
} 

Für weitere Informationen über Closing over the loop variable considered harmful einen Blick auf Eric Lippert Blog-Post nehmen könnte.

+0

_ "Die" für "-Schleife wird nicht geändert." _ Auch wenn ich immer noch .NET 4 benutze, ist dieses Problem auch auf Leute bezogen, die C# 5 bereits benutzen. –

+0

Ja, das ist eines der Probleme mit der brechenden Änderung von foreach-Schleifen in C# 5. In gewisser Weise verhalten sie sich jetzt anders als for-Schleifen. – Dirk

6

Dies geschieht wahrscheinlich, weil der Wert von i nicht innerhalb der Schleife geschlossen ist - wenn die Schleife beendet, i einen Wert von 2 und dannt[i] wegen verzögerter Ausführung wird ausgewertet haben.

Eine Lösung ist es, eine Schließ Variable innerhalb der Schleife zu erzeugen:

int minDim = someValues.Min(t => t.GetLength(0)); // 2 
IOrderedEnumerable<string[]> orderedValues = someValues.OrderBy(t => t[0]); 
for (int i = 1; i < minDim; i++) 
{ 
    var x = i; 
    orderedValues = orderedValues.ThenBy(t => t[x]); 
} 
someValues = orderedValues.ToList(); 
+0

Danke, ich habe Dirks akzeptiert, weil er "foreach loops pre C# 5" und (jetzt) ​​den Link zu E. Lipperts Blog erwähnt, der alles erklärt. –

+1

@TimSchmelter Schön genug - froh, dass es funktioniert hat. –