2014-06-10 8 views
5

Il titolo suggerisce che ho già un'idea di cosa sta succedendo, ma non riesco a spiegarlo. Ho cercato di ordinare uno List<string[]> dinamicamente da ogni "colonna", iniziando dal primo e finendo con il minimo Length di tutti gli array.L'esecuzione differita di For-Loop e LINQ non funziona bene insieme

Quindi, in questo campione è 2, perché l'ultima string[] ha solo due elementi:

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" }); 

Ora ho cercato di ordinare tutto dalla prima e seconda colonna. Potrei farlo in modo statico in questo modo:

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

Ma se non so il numero di "colonne" potrei usare questo ciclo (che è quello che ho pensato):

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 

Ma questo non funziona, fallisce con uno IndexOutOfRangeException nell'ultima riga. Il debugger mi dice che i è 2 in quel momento, quindi la condizione del ciclo sembra essere ignorata, i è già == minDim.

Perché è così? Qual è il modo corretto per questo?

risposta

7

E 'lo stesso problema come un sacco di persone avevano con foreach loop pre C# 5.

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

Il valore di i non sarà valutato fino a quando non si chiama .ToList() a quel punto è 2 poiché questa è la condizione di uscita del ciclo for.

è possibile introdurre una nuova variabile locale all'interno del ciclo for per risolvere il problema:

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

Per ulteriori informazioni si potrebbe dare un'occhiata al post sul blog di Eric Lippert su Closing over the loop variable considered harmful.

+0

_ "Il ciclo" for "non verrà modificato." _ Quindi, anche se sto ancora utilizzando .NET 4, questo problema riguarda anche le persone che stanno già utilizzando C# 5. –

+0

Sì, questo è uno dei problemi con il cambio di rotta di foreach-loop in C# 5. In un modo che ora si comportano in modo diverso rispetto a for-loops. – Dirk

6

Questo è probabilmente accade perché il valore della i non è chiuso all'interno del ciclo - quando l'uscita dal ciclo, i avranno un valore di 2 e poit[i] saranno valutati a causa di esecuzione differita.

Una soluzione è quella di creare una variabile chiusura all'interno del ciclo:

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

Grazie, ho accettato Dirks perché ha menzionato "foreach loop pre C# 5" e (ora) il link al blog di E. Lippert che spiega tutto. –

+1

@TimSchmelter Abbastanza giusto - contento che tu abbia funzionato. –

Problemi correlati