I have this function for sorting by multiple user selected columns:
我有这个功能,可以按多个用户选择的列进行排序:
public override void Sort(SortFields sortFields)
{
if (sortFields == null || sortFields.Count() == 0) return;
var res = FilteredItems.OrderBy(o => o[sortFields[0].Name], sortFields[0].Ascending ? comparer : comparerDesc);
for (int x = 1; x < sortFields.Count(); x++)
res = res.ThenBy(o => o[sortFields[x].Name], sortFields[x].Ascending ? comparer : comparerDesc);
FilteredItems = new BindingList<T>(res.ToList());
if (ListChanged != null)
ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, null));
}
The problem, of course, is that when res.ToList() is called x has been incremented to one greater than the highest index in the list and it throws an error. I know I could go ahead and do a ToList() after each sort but that defeats the purpose and isn't even guaranteed to sort correctly with all linq providers. I'm sure there's a simple solution to this... anyone want to tell me what it is? :)
当然,问题是当调用res.ToList()时,x已经增加到大于列表中最高索引的值,并且它会引发错误。我知道我可以继续在每次排序之后执行ToList(),但是这会破坏目的,甚至不能保证与所有linq提供程序正确排序。我相信这有一个简单的解决方案......任何人都想告诉我它是什么? :)
2 个解决方案
#1
4
It looks like you may be getting tripped up by a closure over the variable x
.
看起来你可能会因变量x的闭包而被绊倒。
That single variable is incremented on every iteration of the loop. It's incremented one last time, at which point it's 1 greater than the number of items in "sortFields", your conditional statement evaluates to False
, and your for
loop ends.
该单个变量在循环的每次迭代时递增。它最后一次递增,此时它比“sortFields”中的项目数大1,条件语句的计算结果为False,并且for循环结束。
As user2864740 pointed out, and Eric states in his article:
正如user2864740指出的那样,Eric在他的文章中说:
Closures close over variables, not over values.
闭包关闭变量,而不是值。
So when you then call ToList()
, your chained ThenBy
statements retain the final value of the variable x
, which was 1 greater than the highest index.
因此,当您调用ToList()时,链接的ThenBy语句将保留变量x的最终值,该值比最高索引大1。
Instead, assign the incrementer to an intermediary variable inside the loop. When you call ToList()
, the final value of x
won't matter.
而是将增量器分配给循环内的中间变量。当您调用ToList()时,x的最终值无关紧要。
for (int x = 1; x < sortFields.Count(); x++)
{
int y = x;
res = res.ThenBy(o => o[sortFields[y].Name], sortFields[y].Ascending ? comparer : comparerDesc);
}
Also from Eric's article, this is (hopefully) being corrected soon, though only in foreach
loops apparently, not for
loops:
同样来自Eric的文章,这是(希望)很快就会被纠正,虽然只是在foreach循环中显然,而不是循环:
In C# 5, the loop variable of a foreach will be logically inside the loop, and therefore closures will close over a fresh copy of the variable each time. The "for" loop will not be changed.
在C#5中,foreach的循环变量将在逻辑上位于循环内部,因此闭包每次都会关闭变量的新副本。 “for”循环不会改变。
#2
0
Try
尝试
var res = FilteredItems.OrderBy(o => o[sortFields[0].Name], sortFields[0].Ascending ? comparer : comparerDesc).ToList();
var res = FilteredItems.OrderBy(o => o [sortFields [0] .Name],sortFields [0] .Ascending?comparer:comparerDesc)。ToList();
#1
4
It looks like you may be getting tripped up by a closure over the variable x
.
看起来你可能会因变量x的闭包而被绊倒。
That single variable is incremented on every iteration of the loop. It's incremented one last time, at which point it's 1 greater than the number of items in "sortFields", your conditional statement evaluates to False
, and your for
loop ends.
该单个变量在循环的每次迭代时递增。它最后一次递增,此时它比“sortFields”中的项目数大1,条件语句的计算结果为False,并且for循环结束。
As user2864740 pointed out, and Eric states in his article:
正如user2864740指出的那样,Eric在他的文章中说:
Closures close over variables, not over values.
闭包关闭变量,而不是值。
So when you then call ToList()
, your chained ThenBy
statements retain the final value of the variable x
, which was 1 greater than the highest index.
因此,当您调用ToList()时,链接的ThenBy语句将保留变量x的最终值,该值比最高索引大1。
Instead, assign the incrementer to an intermediary variable inside the loop. When you call ToList()
, the final value of x
won't matter.
而是将增量器分配给循环内的中间变量。当您调用ToList()时,x的最终值无关紧要。
for (int x = 1; x < sortFields.Count(); x++)
{
int y = x;
res = res.ThenBy(o => o[sortFields[y].Name], sortFields[y].Ascending ? comparer : comparerDesc);
}
Also from Eric's article, this is (hopefully) being corrected soon, though only in foreach
loops apparently, not for
loops:
同样来自Eric的文章,这是(希望)很快就会被纠正,虽然只是在foreach循环中显然,而不是循环:
In C# 5, the loop variable of a foreach will be logically inside the loop, and therefore closures will close over a fresh copy of the variable each time. The "for" loop will not be changed.
在C#5中,foreach的循环变量将在逻辑上位于循环内部,因此闭包每次都会关闭变量的新副本。 “for”循环不会改变。
#2
0
Try
尝试
var res = FilteredItems.OrderBy(o => o[sortFields[0].Name], sortFields[0].Ascending ? comparer : comparerDesc).ToList();
var res = FilteredItems.OrderBy(o => o [sortFields [0] .Name],sortFields [0] .Ascending?comparer:comparerDesc)。ToList();