标题表明我已经知道发生了什么,但我无法解释。我试图通过每个“列”动态订购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" });
现在我试图通过第一和第二列排序。我可以用这种方式静态地做到这一点:
someValues = someValues
.OrderBy(t => t[0])
.ThenBy(t => t[1])
.ToList();
但如果我不知道“列”的数量,我可以使用这个循环(这就是我的想法):
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
但是这不起作用,它在最后一行失败了IndexOutOfRangeException
。调试器告诉我那时i
是2
,因此似乎忽略了for循环条件,i
已经== minDim
。
为什么会这样?这是正确的方法是什么?
答案 0 :(得分:7)
这与许多人在C#5之前使用foreach
循环的问题相同。
orderedValues = orderedValues.ThenBy(t => t[i]);
i
的值只有在你调用.ToList()
时才会被评估,因为那是for循环的退出条件。
您可以在for循环中引入一个新的局部变量来修复它:
for (int i = 1; i < minDim; i++)
{
var tmp = i;
orderedValues = orderedValues.ThenBy(t => t[tmp]);
}
有关更多信息,您可以查看Eric Lippert关于Closing over the loop variable considered harmful的博客文章。
答案 1 :(得分:6)
可能会发生这种情况,因为i
的值未在循环内关闭 - 当循环退出时,i
的值为2
而则因为延迟执行,将评估em> 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();