Henley Wing Chiu
Henley Wing Chiu

Reputation: 22515

C#: sort list of objects by DateTime property that is nullable

I have a List of objects: List<FakeObject> list = ...

Each object has a DateTime property, let's call it "Date"

I want to sort this list by this date property in descending order. However, when I try

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

it complains because the Date property can be nullable.

How do I sort this list, where it treats nullable dates as MAX DATE, so it appears in the top? The quick easy alternative for me is to NOT make the Date field nullable, but let's suppose that's not an option right now.

In short: How do I sort a list of objects by DateTime, if the DateTime can be null?

Upvotes: 8

Views: 9930

Answers (5)

Nicholas Carey
Nicholas Carey

Reputation: 74277

I'd do something like this.

First, given a class like this

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

I'd write a custom comparer, something like this:

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 ;
  }

}

Then it's a simple matter of

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

where true specifies to collate nulls higher than anything else and false to collate them lower than anything else.

Upvotes: 0

Mike Perrenoud
Mike Perrenoud

Reputation: 67898

One possible approach might be:

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

UPDATE: modified to use MaxDate after the OP edited the question for clarification.

Note that you could do this either way (MinDate or MaxDate). The bottom line is this, if it's null then give it some static value that accomplishes what you want.

Upvotes: 16

Tim S.
Tim S.

Reputation: 56536

If you can replace the list, instead of modifying it in-place, you can use LINQ.

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

Upvotes: 6

Code Monkey
Code Monkey

Reputation: 643

How about just setting the null date instances to MAX before the comparision?

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

...followed by the call to your compare..

Upvotes: 0

Servy
Servy

Reputation: 203834

If you want to convert all null dates to the max date value then just do that in your function. You can use the null coalesce operator for a more succinct syntax for this:

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

Upvotes: 8

Related Questions