C#: сортировка списка объектов по свойству DateTime, которое является nullable

у меня есть список объектов: List<FakeObject> list = ...

каждый объект имеет свойство DateTime, назовем его "Date"

Я хочу отсортировать этот список по этому свойству даты в порядке убывания. Однако, когда я пытаюсь

list.Sort(new Comparison<FakeObject>((x, y) => DateTime.Compare(x.Date, y.Date)))

Он жалуется, потому что свойство Date может быть nullable.

как отсортировать этот список, где он обрабатывает нулевые даты как максимальную дату, поэтому он появляется в верхней части? Быстрая легкая альтернатива для меня-не назначать дату поле nullable, но предположим, что это не вариант прямо сейчас.

короче говоря: как отсортировать список объектов по DateTime, если DateTime может быть null?

5 ответов


одним из возможных подходов может быть:

list.Sort(new Comparison<FakeObject>((x, y) => 
    -DateTime.Compare(x.Date ?? DateTime.MaxValue,
        y.Date ?? DateTime.MaxValue)));

обновление: изменен, чтобы использовать MaxDate после того, как OP отредактировал вопрос для уточнения.

обратите внимание, что вы можете сделать это в любом случае (MinDate или MaxDate). Суть в следующем, если это null затем дайте ему некоторое статическое значение, которое выполняет то, что вы хотите.


Если вы хотите преобразовать все нулевые даты в максимальное значение даты, просто сделайте это в своей функции. Для более краткого синтаксиса можно использовать оператор null coalesce:

list.Sort((x, y) => 
    DateTime.Compare(x.Date ?? DateTime.MaxValue, y.Date ?? DateTime.MaxValue))

Если вы можете заменить список, вместо того, чтобы изменять его на месте, вы можете использовать LINQ.

list = list.OrderByDescending(x => x.Date ?? DateTime.MaxValue).ToList();

Как насчет того, чтобы просто установить нулевые экземпляры даты в MAX перед сравнением?

list.ForEach(x => x.Date = x.Date ?? null : DateTime.Max : x.Date);

...затем следует призыв к вашему сравнению..


Я бы сделал что-то вроде этого.

во-первых, учитывая класс такой

class Widget
{
    public DateTime? DateCreated { get ; set ; }
}

Я бы написал пользовательский компаратор, что-то вроде этого:

class Widget
{
  public DateTime? DateCreated { get ; set ; }
}

class WidgetComparer : IComparer<Widget> , IComparer<DateTime?>
{
  public bool NullCollatesHigh { get ; private set ; }
  private WidgetComparer( bool nullCollatesHigh )
  {
    this.NullCollatesHigh = nullCollatesHigh ;
    return ;
  }

  public int Compare( Widget x , Widget y )
  {
    int cc ;

    if      ( x == null && y == null ) cc = 0 ;
    else if ( x != null && y != null ) cc = Compare( x.DateCreated , y.DateCreated ) ;
    else if ( NullCollatesHigh       ) cc = x == null ? +1 : -1 ;
    else                               cc = x == null ? -1 : +1 ;

    return cc ;
  }
  public int  Compare(DateTime? x, DateTime? y)
  {
    int cc ;

    if      ( x == null && y == null ) cc = 0 ;
    else if ( x != null && y != null ) cc = DateTime.Compare( x.Value , y.Value ) ;
    else if ( NullCollatesHigh       ) cc = x == null ? +1 : -1 ;
    else                               cc = x == null ? -1 : +1 ;

    return cc ;
  }

}

тогда это простой вопрос

widgetList.Sort( new WidgetComparer( true/false ) ) ;

здесь true указывает для сортировки нулей выше, чем что-либо еще и false чтобы сопоставить их ниже, чем что-либо еще.