Tim*_*ter 5 c# linq for-loop .net-4.0
标题表明我已经知道发生了什么,但我无法解释.我试图List<string[]>通过每个"列"动态地命令,从第一个开始,以Length所有数组的最小值结束.
所以在这个样本中2,因为最后string[]只有两个元素:
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" });
Run Code Online (Sandbox Code Playgroud)
现在我试图通过第一和第二列排序.我可以用这种方式静态地做到这一点:
someValues = someValues
.OrderBy(t => t[0])
.ThenBy(t => t[1])
.ToList();
Run Code Online (Sandbox Code Playgroud)
但如果我不知道"列"的数量,我可以使用这个循环(这就是我的想法):
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
Run Code Online (Sandbox Code Playgroud)
但这不起作用,它IndexOutOfRangeException在最后一行失败了.调试器告诉我,i就是2在那个时候,这样的for循环条件似乎被忽略,i已经是== minDim.
为什么会这样?这是正确的方法是什么?
这与许多人在foreachC#5 之前的循环一样是个问题.
orderedValues = orderedValues.ThenBy(t => t[i]);
Run Code Online (Sandbox Code Playgroud)
i直到你调用.ToList()它为2时才会计算值,因为那是for循环的退出条件.
您可以在for循环中引入一个新的局部变量来修复它:
for (int i = 1; i < minDim; i++)
{
var tmp = i;
orderedValues = orderedValues.ThenBy(t => t[tmp]);
}
Run Code Online (Sandbox Code Playgroud)
有关更多信息,您可以查看Eric Lippert关于关闭环路变量被认为有害的博客文章.
这可能发生,因为价值i的循环中没有关闭-循环退出时,i将有一个价值2,并随后 t[i]将推迟,因为执行进行评估.
一种解决方案是在循环中创建一个结束变量:
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();
Run Code Online (Sandbox Code Playgroud)