【问题标题】:LINQ new instance when SingleOrDefault returns nullSingleOrDefault 返回 null 时的 LINQ 新实例
【发布时间】:2012-12-30 18:55:15
【问题描述】:

我有这个简单的方法:

    #region Fields

    private Collection<Address> _addresses;

    #endregion

    #region Public methods

    public Address DeliveryAddress()
    {
        if (_addresses == null)
            if (this.Id > 0)
                _addresses = Core.Data.Addresses.GetClient(this.Id);

        return _addresses.SingleOrDefault(x => x.TypeId == AddressType.Delivery);
    }

    public Address InvoiceAddress()
    {
        if (_addresses == null)
            if (this.Id > 0)
                _addresses = Core.Data.Addresses.GetClient(this.Id);

        return _addresses.SingleOrDefault(x => x.TypeId == AddressType.Invoice);
    }

    #endregion

如您所见,我试图为DeliveryAddress 返回一个结果,为InvoiceAddress 返回一个结果。我的问题是,如果SingleOrDefault 返回null,我希望链接表达式创建Address() 的新实例。 我对 linq 真的很陌生,所以我不确定 SingleOrDefault 是否是我应该使用的正确表达式。

【问题讨论】:

标签: c# asp.net linq


【解决方案1】:

您可以使用 DefaultIfEmpty 并将该实例用作默认值:

return _addresses.Where(x => x.TypeId == AddressType.Delivery)
                 .DefaultIfEmpty(new Adress())
                 .Single();

【讨论】:

  • 这种情况下你也可以使用Single代替SingleOrDefault
  • @w0lf 是的,这样就不会那么混乱了。
【解决方案2】:

使用null-coalescing operator

return _addresses
    .SingleOrDefault(x => x.TypeId == AddressType.Delivery) ?? new Address();

表达式

x ?? y

如果x 不是null,则产生x,否则产生y。您可以链接操作员

x ?? y ?? z ?? t

如果它们都是null,则返回第一个非空值或null


更新

请注意,SingleOrDefault 如果序列包含多个元素,则会引发异常。如果您需要可能没有或超过一个元素的序列的第一个元素,请改用FirstOrDefault

【讨论】:

    【解决方案3】:

    您可以创建自己的扩展方法,如下所示:

    public static T NewIfNull<T>(this T obj) where T: class, new()
    {
       return obj ?? new T();
    }
    

    ...然后在 SingleOrDefault 的末尾添加一个用法:

    var singleResult = myCollection.SingleOrDefault().NewIfNull();
    

    ...或者因为逻辑很简单,就像其他答案所说的那样内联。

    【讨论】:

      【解决方案4】:

      代替

      return _addresses.SingleOrDefault(x => x.TypeId == AddressType.Delivery);
      

      做这样的事情:

      var address = _addresses.SingleOrDefault(x => x.TypeId == AddressType.Delivery);
      
      if(address == null)
          address = new Address();
      
      return address;
      

      【讨论】:

        【解决方案5】:

        我倾向于将这两种方法都写为IEnumerable&lt;Address&gt; 上的扩展方法。如果 SingleOrDefault() 调用返回 null,您可以使用 null-coalesing 运算符返回一个新实例。

        public static class AddressExtensions
        {
            public static Address DeliveryAddress(this IEnumerable<Address> addresses)
            {
                return addresses.SingleOrDefault(x => x.TypeId == AddressType.Delivery) 
                       ?? new Address();
            }
        
            public static Address InvoiceAddress(this IEnumerable<Address> addresses)
            {
                return addresses.SingleOrDefault(x => x.TypeId == AddressType.Invoice) 
                       ?? new Address();
            }
        }
        

        【讨论】:

          【解决方案6】:

          除了其他答案中的替代方案外,您还可以创建自己的SingleOrNew扩展方法。

          public static TSource SingleOrNew<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate ) where T:new()
          {
               return source.SingleOrDefault(predicate) ?? new T();
          }
          

          它可以用作

          return _addresses.SingleOrNew(x => x.TypeId == AddressType.Delivery);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多