【问题标题】:NullReferenceException when using Group.FirstOrDefault with Value Type将 Group.FirstOrDefault 与值类型一起使用时出现 NullReferenceException
【发布时间】:2013-07-26 14:22:15
【问题描述】:

这是一个 linq 表达式的摘录:

Dim charges As List(Of IndividualCharge) = (From t In totals
                    Group t By t.InvId
                    Into Group
                    Select New IndividualCharge With {
                    .VatRate = Group.FirstOrDefault(Function(x) x.VatRate).VatRate
                    }).ToList()

看来x.VatRate为0时,FirstOrDefault抛出异常:

我可以通过换掉它来确认这一点:

.VatRate = Group.FirstOrDefault(Function(x) 0).VatRate

确保每次都出现异常。

  • 为什么会抛出空引用异常(这是一个值类型,因此没有引用)?
  • x.VatRate 实际上是0 的情况如何处理?

【问题讨论】:

  • @Skippy - 意义不相关
  • 我没有像你想的那样做任何除法
  • 在这种情况下它只是一个数字

标签: .net vb.net linq linq-expressions


【解决方案1】:

您误读了错误,加上 VB.NET 的类型强制。

Group.FirstOrDefault(Function(x) x.VatRate).VatRate

FirstOrDefault 返回与谓词函数匹配的第一个值,如果没有匹配项,则返回默认值 T。由于您的函数不会评估为true 或false,VB.NET 将int 强制为bool。在那种情况下,0 is converted to false and any other value is converted to true。

所以,当x.VatRate 不是0 时,那么第一个IndividualCharge 通过谓词过滤器。当VatRate 为0 时,则没有IndividualCharge 通过谓词过滤器并返回null(默认值IndividualCharge)。尝试获取VatRate 然后会导致您的NullReferenceException。

大概你真的想要第一个VatRate,不管它是否为0。将您的代码更改为:

Group.Select(Function(x) x.VatRate).First()

应该做到这一点。

【讨论】:

    【解决方案2】:

    当您将表达式传递给 FirstOrDefault 时,您会告诉它选择与表达式匹配的第一个项目(很像 Where 子句,但要匹配该子句的第一个对象)。如果您将您的陈述更改为以下内容可以吗?

    Dim charges As List(Of IndividualCharge) = (From t In totals
                        Group t By t.InvId
                        Into Group
                        Select New IndividualCharge With {
                        .VatRate = Group.FirstOrDefault().VatRate
                        }).ToList()
    

    如果您想获得第一个不为零的值,那么应该按照这些方式进行操作?

    Dim charges As List(Of IndividualCharge) = (From t In totals
                        Group t By t.InvId
                        Into Group
                        Select New IndividualCharge With {
                        .VatRate = if(Group.Any(function(o) o.VatRate > 0),  Group.FirstOrDefault(function(o) o.VatRate > 0).VatRate, -1)
                        }).ToList()
    

    【讨论】:

      【解决方案3】:

      这是由 VB 的隐式类型强制导致的。 FirstOrDefault 方法需要一个返回 Boolean 的函数。您正在传递一个返回 Decimal 的函数,因此 VB 将其转换为:

      Group.FirstOrDefault(Function(x) x.VatRate <> 0)
      

      如果组中的所有项目都没有非零的VatRate,这将返回Nothing。然后,您尝试访问返回对象的 VatRate 属性,这会导致 NullReferenceException。

      尝试使用:

      Group.Where(Function(x) x.VatRate <> 0)
         .Select(Function(x) x.VatRate)
         .FirstOrDefault()
      

      如果有一个,则应该返回第一个非零VatRate,否则返回零。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-28
        • 1970-01-01
        • 2019-03-20
        • 2021-11-21
        • 2021-05-12
        • 1970-01-01
        • 2013-12-31
        • 2020-06-27
        相关资源
        最近更新 更多