У меня есть эта функция для сортировки по нескольким выбранным пользователем столбцам:
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));
}
Проблема, конечно, в том, что когда res.ToList() называется x, увеличивается на один, превышающий самый высокий индекс в списке, и он выдает ошибку. Я знаю, что могу пойти вперед и сделать ToList() после каждого вида, но это побеждает цель, и даже не гарантируется корректная сортировка со всеми поставщиками linq. Я уверен, что есть простое решение для этого... кто-нибудь хочет сказать мне, что это такое? :)
Похоже, что вы можете столкнуться с закрытием по переменной x
.
Эта единственная переменная увеличивается на каждой итерации цикла. Он увеличился в последний раз, и в этот момент он на 1 больше числа элементов в "sortFields", ваш условный оператор оценивается как " False
, а ваш цикл for
заканчивается.
Как указал пользователь2864740, и Эрик утверждает в своей статье:
Закрытие закрывается над переменными, а не над значениями.
Поэтому, когда вы вызываете ToList()
, ваши ThenBy
выражения ThenBy
сохраняют окончательное значение переменной x
, которая на 1 больше, чем самый высокий индекс.
Вместо этого присвойте инкремент промежуточной переменной внутри цикла. Когда вы вызываете 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);
}
Также из статьи Эрика это (надеюсь) будет исправлено в ближайшее время, хотя только в петлях foreach
видимому, не for
циклов:
В С# 5 переменная цикла foreach будет логически внутри цикла, и поэтому замыкания будут закрываться по новой копии переменной каждый раз. Цикл "для" не будет изменен.
Пытаться
var res = FilteredItems.OrderBy(o => o[sortFields[0].Name], sortFields[0].Ascending? comparer: comparerDesc).ToList();
y
отличается или «свежа» в каждом цикле (где переменнаяx
одинакова), а замыкания связываются с переменными, а не со значениями.