Reputation: 17422
I have one list
with few records, list
has another object
inside it. Based on inner object I am using OrderByDescending
. Inner object is null
in few places so it is throwing NullReferenceException
.
items.OrderByDescending(i=> i.Obj_Announcement.CreatedDate).ToList()
When Obj_Announcement
is null
the query throws an exception.
Not duplicate: I have object inside OrderByDescending
not single field.
How can I solve this issue?
Upvotes: 0
Views: 1534
Reputation: 30454
The neat method would be to separate your LINQ query from the way you define which item comes before another item. In other word: what is the sort order of Item X and Item Y
For this we need to create a class that implements IComparer<Item>
class Item
{
public Announcement Announcement {get; set;} // your inner object, might be null
...
}
class Announcement
{
public DateTime CreatedDate {get; set;}
...
}
Suppose you you have two Items
, one of them has a null Anouncement
.
Item item1 = new Item {Announcement = null};
Item item2 = new Item {Announcement = new AnnounceMent{CreatedDate=new DateTime(2000, 1, 1)}};
It's up to you to decide which comes first. Let's assume you want the null items at the end.
class ItemComparer : Comparer<Item>
{
public static readonly ByCreatedDate = new ItemComparer();
private static readonly IComparer<DateTime> dateComparer = Comparer<DateTime>.default;
public override int CompareTo(Item x, Item y)
{
// TODO: decide what to do if x or y null: exception? comes first? comes last
if (x.Announcement == null)
{
if (y.Announcement == null)
// x and y both have null announcement
return 0;
else
// x.Announcement null, y.Announcement not null: x comes last:
return +1;
}
else
{
if (y.Announcement == null)
// x.Announcement not null and y.Announcement null; x comes first
return -1;
else
// x.Announcement not null, y.Announcement not null: compare dates
return dateComparer.CompareTo(x.CreatedDate, y.CreateDate)
}
}
}
Usage:
(improved after comment by Peter Wurzinger)
var result = items.OrderByDescending(item => item, ItemComparer.ByCreatedDate);
Note: If you decide to change the sort order of your Items, all you have to do is change the ItemComparer class. All your LINQ statements that order your Items will then use the new sort order.
Upvotes: 3
Reputation: 3053
items.OrderByDescending(i=> i.Obj_Announcement?.CreatedDate ?? DateTime.MinValue).ToList()
should work, as if the value is null, it will return DateTime.MinValue
(meaning null values will be at the back), and otherwise, you will just retrieve the CreatedDate.
Please note that I am not in front of a pc right now though, so could not test.
Upvotes: 1
Reputation: 411
You basically got two options depending on the resulting set you're expecting.
Exclude the instances, which's Obj_Announcement
- property is null. But imho that's not the scope of the question and would change the beavior of the program.
Explicitly decide on how to deal with nulls.
When looking at the documentation for OrderByDescending
(https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.orderbydescending) one comes across the keySelector
parameter. Since it's a Func<TSource, TKey>
it should be able to deal edge cases a TSource
instance could show - for example nulls on a child-object, in your case.
So imho the easiest solution on how to deal with that would be deciding whether you want to prepend or append the nulls to the list by
items.OrderByDescending(i=> i.Obj_Announcement?.CreatedDate ?? DateTime.MinValue).ToList()
or
items.OrderByDescending(i=> i.Obj_Announcement?.CreatedDate ?? DateTime.MaxValue).ToList()
But be aware, that DateTime.MinValue
and DateTime.MaxValue
are only assumptions as default values. They do not reflect the actual state of the object.
Upvotes: 2