C# 检查orderby Linq中的对象null

C# 检查orderby Linq中的对象null,c#,linq,C#,Linq,我有一个列表几乎没有记录,列表中有另一个对象。基于内部对象,我使用的是OrderByDescending。内部对象在少数位置为null,因此它正在抛出NullReferenceException items.OrderByDescending(i=> i.Obj_Announcement.CreatedDate).ToList() 当Obj_Announcement为null时,查询抛出异常 不重复:我在OrderByDescending中有对象,而不是单个字段 我如何解决这个问题 it

我有一个
列表
几乎没有记录,
列表
中有另一个
对象
。基于内部对象,我使用的是
OrderByDescending
。内部对象在少数位置为
null
,因此它正在抛出
NullReferenceException

items.OrderByDescending(i=> i.Obj_Announcement.CreatedDate).ToList()
Obj_Announcement
null
时,查询抛出异常

不重复:我在
OrderByDescending
中有对象,而不是单个字段

我如何解决这个问题

items.OrderByDescending(i=> i.Obj_Announcement?.CreatedDate ?? DateTime.MinValue).ToList()
如果该值为null,则它将返回
DateTime.MinValue
(意味着null值将在后面),否则,您将只检索CreatedDate


请注意,我现在不在电脑前,因此无法测试。

根据预期的结果集,您基本上有两个选项

  • 排除实例,
    Obj_Announcement
    -属性为空。但我认为这不是问题的范围,它会改变这个项目的前景

  • 明确决定如何处理空值

  • 查看
    OrderByDescending
    ()文档时,会遇到
    keySelector
    参数。由于它是一个
    Func
    函数,它应该能够处理
    TSource
    实例可能显示的边缘情况,例如,在您的情况下,子对象上的空值。 因此,解决这个问题的最简单的方法是,通过

    items.OrderByDescending(i=> i.Obj_Announcement?.CreatedDate ?? DateTime.MinValue).ToList()
    


    但是请注意,
    DateTime.MinValue
    DateTime.MaxValue
    只是作为默认值的假设。它们并不反映对象的实际状态。

    最简洁的方法是将LINQ查询与定义哪个项位于另一项之前的方式分开。换句话说,项目X和项目Y的排序顺序是什么

    为此,我们需要创建一个实现
    IComparer

    假设您有两个
    ,其中一个有空的
    声明

    Item item1 = new Item {Announcement = null};
    Item item2 = new Item {Announcement = new AnnounceMent{CreatedDate=new DateTime(2000, 1, 1)}};
    
    由你决定谁先来。让我们假设您希望在末尾有空项

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

    注意:如果您决定更改项目的排序顺序,您所要做的就是更改ItemComparer类。所有对项目进行排序的LINQ语句都将使用新的排序顺序。

    要解决此问题,您应首先决定
    null
    值应如何排序。它们应该是最低的还是最高的?@RenéVogt-我需要最新的记录在顶部,这样我就需要了。网络库不允许DateTime对象为空。通常我使用一个新的DateTime,它将默认日期设置为1/1/1。然后,我通过检查日期是否大于1/1/1来测试空值。您应该对内部对象的hasValue排序,然后根据其值对列表排序:
    items.OrderByDescending(I=>I.Obj_Announcement.CreatedDate.hasValue)。然后通过Descending(I=>I.Obj_Announcement.CreatedDate.value)
    +1,这是一个很好的答案!但是我认为,
    OrderByDescending(IEnumerable,IComparer)
    根据。Imho调用因此应该看起来像
    items.OrderByDescending(item=>item,ItemComparer.ByCreatedDate)
    应该注意的是,当与
    IQueryable
    like或mapping、OData或任何东西一起使用时,它很可能不可翻译。
    Item item1 = new Item {Announcement = null};
    Item item2 = new Item {Announcement = new AnnounceMent{CreatedDate=new DateTime(2000, 1, 1)}};
    
    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)
             }
        }
    }
    
    var result = items.OrderByDescending(item => item, ItemComparer.ByCreatedDate);