Nullable对象必须在IComparable.CompareTo中具有值

时间:2015-07-01 15:57:47

标签: asp.net vb.net

我有一个需要使用Nullable(of Double)属性进行排序的自定义类。我已经定义了这个类,并实现了iCompare。在我的代码中,我想到我已经对Null值进行了足够的检查,但我突然看到了这个错误......

  

Nullable对象必须有值。

......在这一行:

Return Me.SomeDouble.Value.CompareTo(CType(obj, MatrixCellData).SomeDouble.Value)

任何人都可以解释为什么会这样吗?我知道通常使用我已包含的Double.HasValue可以轻松避免此错误。要重现的完整示例代码如下。

Namespace MyApp

    Public Class MatrixCellData
        Implements IComparable

        Public Property SomeDouble As Nullable(Of Double)

        Public Function CompareTo(obj As Object) As Integer Implements System.IComparable.CompareTo
            If obj Is Nothing OrElse IsDBNull(obj) OrElse Not TypeOf (obj) Is MatrixCellData Then
                Return 1
            Else
                If Not Me.SomeDouble.HasValue Then
                    Return -1
                Else
                    Return Me.SomeDouble.Value.CompareTo(CType(obj, MatrixCellData).SomeDouble.Value)
                End If
            End If
        End Function

    End Class

End Namespace

打破代码......

Dim lst As New List(Of MyApp.MatrixCellData)
lst.Add(New MyApp.MatrixCellData With {.SomeDouble = 75})
lst.Add(New MyApp.MatrixCellData With {.SomeDouble = 25})
lst.Add(New MyApp.MatrixCellData With {.SomeDouble = Nothing})
lst.Sort() ' Triggers error

1 个答案:

答案 0 :(得分:1)

如果您不使用

Declare @Dates as nvarchar(max); 
--Builds up a string of dates for the last 4 months. 
Set @Dates = left(datename(Month, datefromparts(year(dateadd(month, -3, getdate())), month(getdate())-3, 1)), 3) + 
 right(datename(year, datefromparts(year(dateadd(month, -3, getdate())), month(getdate())-3, 1)), 2) + ',' +
 left(datename(Month, datefromparts(year(dateadd(month, -2, getdate())), month(getdate())-2, 1)), 3) + 
 right(datename(year, datefromparts(year(dateadd(month, -2, getdate())), month(getdate())-2, 1)), 2)+ ',' +
 left(datename(Month, datefromparts(year(dateadd(month, -1, getdate())), month(getdate())-1, 1)), 3) + 
 right(datename(year, datefromparts(year(dateadd(month, -1, getdate())), month(getdate())-1, 1)), 2)+ ',' +
 left(datename(Month, getdate()), 3) + 
 right(datename(year, getdate()), 2);


EXEC('Select *
 from
(
Select  
    capj.cnsmr_accnt_id,
    wrkgrp_nm,
    max(UDEFINST_AMT) as Instlmnt,
    sum(cnsmr_accnt_pymnt_amnt) as Mnth_Tot, 
--Gives the Month & year (Eg Jul15)
    left(datename(Month, cnsmr_accnt_pymnt_pstd_dt), 3) + right(datename(year, cnsmr_accnt_pymnt_pstd_dt), 2) as Month_Yr
from 
    dbo.cnsmr_accnt_pymnt_jrnl capj  
        inner join 
    UDEFGENERAL UG 
        on 
        capj.cnsmr_accnt_id = UG.cnsmr_accnt_id
        Inner join
    wrkgrp w 
        on
        capj.wrkgrp_id = w.wrkgrp_id
where
cnsmr_accnt_pymnt_stts_cd in (5)
and cnsmr_accnt_pymnt_pstd_dt between
--Go back to the 1st day 4 months back
datefromparts(year(dateadd(month, -3, getdate())), month(getdate())-3, 1)
and 
getdate()
group by capj.cnsmr_accnt_id, 
left(datename(Month, cnsmr_accnt_pymnt_pstd_dt), 3) + right(datename(year, cnsmr_accnt_pymnt_pstd_dt), 2), 
 wrkgrp_nm) as Mnth_Tot_Tbl
 pivot 
 (
 sum(Mnth_Tot) 
 for 
 Month_Yr in (' + @Dates + ')) as Piv')

然后没有检查阻止Me.SomeDouble等于Nothing。

当您在列表中调用sort函数时,您将为每个项目至少调用一次CompareTo函数。实际上,框架会尝试将最后一项放在有序列表中的某个位置,调用看起来与此类似:

If Not Me.SomeDouble.HasValue Then

以下所有检查均为假:

(New MatrixCellData With {.SomeDouble = Nothing}).CompareTo(New MatrixCellData With {.SomeDouble = 25})

Obj不是Nothing,(Me.SomeDouble是Nothing)

这意味着您在CompareTo方法中的最后一行

If obj Is Nothing OrElse IsDBNull(obj) OrElse Not TypeOf (obj) Is MatrixCellData Then

在Me.SomeDouble为Nothing的情况下,实际上是:

Return Me.SomeDouble.Value.CompareTo(CType(obj, MatrixCellData).SomeDouble.Value)

这当然没有意义,因为Nothing没有'Value'方法或属性。

我会把它重写为

Return Nothing.Value.CompareTo(CType(obj, MatrixCellData).SomeDouble.Value)

结束功能