与DefaultIfEmpty

时间:2018-04-02 08:40:35

标签: c# linq

我有以下类结构,我需要找到UpdatedDate的最新Order,即Order / Orderline / OrderlineSize / OrderlineVAS的最大值。列表永远不会为空,但可能为空。

class Order
{
    public List<Orderline> Orderlines { get; set; }
    public DateTime UpdatedDate { get; set; }
}

class Orderline
{
    public List<OrderlineSize> OrderLineSizes { get; set; }
    public List<OrderlineVAS> OrderLineValueAddedServices { get; set; }
    public DateTime UpdatedDate { get; set; }
}
class OrderlineSize
{
    public DateTime UpdatedDate { get; set; }
}

class OrderlineVAS
{
    public DateTime UpdatedDate { get; set; }
}

我正在使用以下代码获取Max,如果有OrderLineSizes这样可以正常工作,但当列表为空时会抛出NullReferenceException

(new List<DateTime?>() {
    order.UpdatedDate,
    order.Orderlines.Max(x=>x.UpdatedDate),
    order.Orderlines.SelectMany(x=>x.OrderLineSizes).DefaultIfEmpty()?.Max(y=>y.UpdatedDate),
    order.Orderlines.SelectMany(x=>x.OrderLineValueAddedServices).DefaultIfEmpty()?.Max(y=>y.UpdatedDate)
})
.Max().Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ");

我使用C#6中的elvis操作解决了它,如下所示

(new List<DateTime?>() {
    order.UpdatedDate,
    order.Orderlines.Max(x=>x?.UpdatedDate),
    order.Orderlines.SelectMany(x=>x.OrderLineSizes).Max(y=>y?.UpdatedDate),
    order.Orderlines.SelectMany(x=>x.OrderLineValueAddedServices).Max(y=>y?.UpdatedDate)
})
.Max().Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")

使用早期版本的C#怎么解决?我认为在Linq中使用Select子句但不确定这是否是一个不错的选择。 如何优化它以获得更好的性能?

1 个答案:

答案 0 :(得分:1)

抛出异常:

.DefaultIfEmpty()?.Max(y=>y.UpdatedDate)

DefaultIfEmpty不返回null。相反,它返回一个带有单个null条目的枚举。因此它通过?。到马克斯。最后,在y.UpdateDate处理null,y == null,导致NullReferenceException。

通过删除?解决?从DefaultIfEmpty之后,而是在y之后添加它,如下所示:

.DefaultIfEmpty().Max(y=>y?.UpdatedDate)

这需要在这个模式出现的两行中完成。

此外,整个事情可以更加高效和简洁:

        string result =                
            Enumerable.Repeat(order.UpdatedDate, 1)
                .Concat(order.Orderlines.Select(x1 => x1.UpdatedDate))
                .Concat(order.Orderlines.SelectMany(x => x.OrderLineSizes).Select(x => x.UpdatedDate))
                .Concat(order.Orderlines.SelectMany(x => x.OrderLineValueAddedServices).Select(x => x.UpdatedDate))
                .Max().ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ");