Получить элементы в списке, которые больше, чем выбранный элемент

#c# #linq #compareto #icomparable

#c# #linq #сравнение #icomparable

Вопрос:

У меня есть список Versions .

 List<Version> versions = GetVersions();
  

И у меня есть selectedVersion .

Мой Version класс реализует IComparable .

 public class Version : IComparable<Version>
  

Так что я могу сделать versions.Sort() . На данный момент мои Version объекты отсортированы в списке, скажем, по Name свойству.

Из списка Versions я хотел бы получить элементы, которые выше моего selectedVersion . Как я могу это сделать с помощью Linq?

То, что я пробовал, — это приведение selectedVersion к IComparable , а затем использование CompareTo , но я получаю InvalidCastException сообщение об ошибке.

 IComparable comparable = (IComparable)selectedVersion;
if(comparable.CompareTo(selectedVersion)) > 0
  

Комментарии:

1. Почему вы приводите к IComparable тому, что версия только реализует IComparable<Version> ?

2. IComparable — это метод сравнения объектов, в то время как selectedVersion — это версия типа.

3. @PatrickHuizinga отметил. Я должен приводить к IComparable<Version>

Ответ №1:

Правильный способ — использовать Comparer<T>.Default which будет работать, как только тип T реализует либо IComparable<T> или IComparable :

 var result = versions
    .Where(version => Comparer<Version>.Default.Compare(version, selectedVersion) > 0)
    .ToList();
  

Вы даже можете инкапсулировать его в пользовательский метод расширения (так что вы DRY):

 public static class EnumerableExtensions
{
    public static IEnumerable<T> GreaterThan<T>(this IEnumerable<T> source, T value, IComparer<T> comparer = null)
    {
        if (comparer == null) comparer = Comparer<T>.Defau<
        return source.Where(item => comparer.Compare(item, value) > 0);
    }
}
  

и использовать просто

 var result = versions.GreaterThan(selectedVersion).ToList();
  

Комментарии:

1. Обходной путь? Он-он, это то, что OrderBy , Min , Max внутренне используется, когда вы не указываете явный компаратор, поэтому, я думаю, они считают это решением 🙂

2. Значит, он все еще зависит от моей CompareTo реализации?

3. Абсолютно. Вы можете поставить точку останова и посмотреть. Это просто универсальный метод, поэтому вам не нужно думать, какой именно интерфейс реализован классом.

4. тогда это более общее решение 🙂

Ответ №2:

Похоже, вы реализовали IComparable<T> , что не совпадает с IComparable . Либо реализуйте IComparable , либо приведите к IComparable<Version> , и вы сможете делать то, что хотите.

Ответ №3:

 versions.Where(x => x.CompareTo(selectedVersion) > 0).ToList();
  

или, если IComparable<Version> реализовано явно:

 versions.Where(x => (x as IComparable<Version>).CompareTo(selectedVersion) > 0).ToList();