List.orderBy застревает в бесконечном цикле - PullRequest
0 голосов
/ 22 января 2019

У меня есть List<Expense> myList, где счет содержит 2 поля: decimal Amount и Status ItemStatus. Статус enum {Paid, DueSoon, DueToday, Overdue, Unpaid}.

Я пытался отсортировать список в порядке возрастания или убывания, однако Status.Unpaid всегда должен отображаться последним в порядке возрастания или убывания.

Использование myList.Sort((x, y) => comparer.Compare(x.ItemStatus, y.ItemStatus)) вместе с моим компаратором работало хорошо.

Однако после сортировки списка по ItemStatus я также хотел отсортировать список по Amount. Поэтому я решил использовать myList = myList.OrderBy(x => x.ItemStatus, comparer).ThenBy(x => x.Amount).ToList(), что привело к бесконечному циклу.

Бесконечный цикл был еще там, когда я полностью удалил метод .ThenBy().

Я добавил статический счетчик в свой компаратор для отладки, и метод OrderBy() использовал компаратор 90 раз в списке из 30 расходов до входа в бесконечный цикл.

Это мой компаратор:

class StatusComparer : IComparer<Status>
{
    public bool IsAscending { get; private set; } = true;

    public StatusComparer(bool isAscending)
    {
        IsAscending = isAscending;
    }

    public int Compare(Status x, Status y)
    {
        if (IsUnpaid(x)) { return IsAscending? 1 : -1; }
        if (IsUnpaid(y)) { return IsAscending ? -1 : 1; }


        return x.CompareTo(y);
    }


    private static bool IsUnpaid(Status status)
    {
        return status.CompareTo(Status.Unpaid) == 0;
    }
}

Что я делаю не так или как мне добиться того, что я пытаюсь сделать?

Заранее спасибо.

1 Ответ

0 голосов
/ 22 января 2019

Ваша реализация Compare неверна

public int Compare(Status x, Status y)
{
    if (IsUnpaid(x)) { return IsAscending? 1 : -1; }
    if (IsUnpaid(y)) { return IsAscending ? -1 : 1; }

    return x.CompareTo(y);
}

Представьте, что у нас есть IsAscending == true, IsUnpaid(x) == true и IsUnpaid(y) == true.В этом случае

x.Compare(y) == 1 // so x > y
y.Compare(x) == 1 // so y > x

Вот почему OrderBy вполне может войти в бесконечный цикл (каков правильный порядок для сбора {x, y}, если x > y и y > x?).Вы, наверное, хотите

public int Compare(Status x, Status y) {
  if (IsUnpaid(x)) { 
    if (!IsUnpaid(y))
      return IsAscending ? -1 : 1; // x is UnPaid, y is Paid
  }
  else if (IsUnpaid(y)) { 
    return IsAscending ? 1 : -1;   // x is Paid, y is UnPaid
  }

  // x and y either both Paid or unPaid
  // If IsAscending should be taken into account, use it as below:
  // return IsAscending ? x.CompareTo(y) : y.CompareTo(x);
  return x.CompareTo(y);
}
...