.net 字典上的NullReferenceException。使用字典变量not Null、键not Null和无多线程进行添加

.net 字典上的NullReferenceException。使用字典变量not Null、键not Null和无多线程进行添加,.net,vb.net,exception,.net,Vb.net,Exception,这里有很多类似的问题,但没有一个能解释我的情况;这就来了 我有以下(简化的)代码: ' row is a System.Data.DataRow ' _typeProperties is a Dictionary(Of String, PropertyInfo) Dim data As New Dictionary(Of String, Object) Dim elem As KeyValuePair(Of String, PropertyInfo) Dim value As Object =

这里有很多类似的问题,但没有一个能解释我的情况;这就来了

我有以下(简化的)代码:

' row is a System.Data.DataRow
' _typeProperties is a Dictionary(Of String, PropertyInfo)

Dim data As New Dictionary(Of String, Object)
Dim elem As KeyValuePair(Of String, PropertyInfo)
Dim value As Object = Nothing
Try
    For Each elem In _typeProperties
        value = row.Item(elem.Key)
        data.Add(elem.Key, value)       ' NullReferenceException here
    Next
Catch ex As Exception When MyExceptionFilter(ex, data, elem, value)
End Try
有时我会在指定的行上得到一个NullReferenceException。这个例外非常罕见,我不能随意复制它。然而,我可以修改我的应用程序,将其发送给客户,并且可以肯定,几天后它将自行复制

调用堆栈不是很有用:

StackTrace: 
  XXX.RowToType(DataRow row) in C:\XXX.vb:line 645.
此外,正如您所看到的,我在Catch块中包含了一个异常过滤器。在这里,我编写了一个小型转储(异常的调用堆栈保持不变)。以下是minidump显示的调用堆栈的相关部分:

  ...
  App.exe!MyExceptionFilter( ex,  data,  elem,  value) Line 627
  App.exe!RowToType( row) Line 647 + 0x1f bytes
  [External Code]   
  App.exe!RowToType(System.Data.DataRow row) Line 645 + 0x112 bytes
  App.exe!SomeClass.get_Item(Integer index) Line 1141 + 0xe bytes   
  user32.dll!_InternalCallWinProc@20()  + 0x23 bytes    
  user32.dll!_UserCallWinProcCheckWow@32()  + 0x693 bytes   
  ...
异常发生在[External Code]块的某个地方;然后执行Catch块的过滤器(第2行和第1行)

在发生异常时,以下是三个相关变量的值:

  data: Not Nothing; 
  elem: Not Nothing; 
  elem.Value: Not Nothing (Int32 ID)
  elem.Key: Not Nothing
  value: Nothing
因此,似乎完全没有理由使用data.Add来引发NullReferenceException

正如一些人在其他问题中提出的,可能存在一些线程问题。然而,根据定义,我正在编写的词典只能对一条线程可见。(当然,我还检查了minidump,以确保没有线程执行相同的代码。)

我可能只是默默地忽略了这个异常,但我更愿意找出答案

编辑。对于感兴趣的人,以下是完整的代码:

Private Function RowToType(ByVal row As DataRow) As DataSourceRow
    Dim o = _typeActivator({})
    Dim data As New Dictionary(Of String, Object)
    Dim elem As KeyValuePair(Of String, PropertyInfo) = Nothing
    Dim value As Object = Nothing
    Try
        For Each elem In _typeProperties
            value = row.Item(elem.Key)
            If DBNull.Value.Equals(value) Then value = Nothing
            elem.Value.SetValue(o, value, Nothing)
            data.Add(elem.Key, value)           ' NullReferenceException here
        Next
    Catch ex As Exception When RowToTypeExceptionFilter(ex, row, data, elem, value)
    End Try

    o.Data = data
    Return o
End Function

仅供参考:
\u typeActivator
创建动态类型的实例
o
;不过,不要认为这与问题有关。

value:Nothing
将是获取空引用异常的有效原因。
数据行中的字符串可能是空的(如果该列不存在,则会出现异常)。

查看文档时没有发现任何内容

当您不为对象变量赋值时,它不再引用任何对象实例。如果变量以前引用过实例,将其设置为Nothing不会终止实例本身。只有在垃圾收集器(GC)检测到没有剩余的活动引用之后,实例才会终止,并释放与其关联的内存和系统资源

在将对象设置为“无”之前,系统可能认为该对象具有有效的引用


这可能发生在字典值设置之外,也可能发生在字典本身内部。设置后,链接到关键点的对象可能会被释放

将有助于验证要添加的对象的内容,它可能是DBNull。

' row is a System.Data.DataRow'
' _typeProperties is a Dictionary(Of String, PropertyInfo)'
Dim data As New Dictionary(Of String, Object)

For Each pair As KeyValuePair(Of String, PropertyInfo) In _typeProperties

    'Validates that _typeProperties has no empty or nothing value as key'
    If String.IsNullOrEmpty(pair.Key) Then Continue For

    'Validates that the row contains the specified column'
    If Not row.Table.Columns.Contains(pair.Key) Then Continue For

    data.Add(pair.Key, If(IsDBNull(row(pair.Key)), "", row(pair.Key)))
    'data.Add(pair.Key, CheckNull(Of String)(row(pair.Key)))'
Next

“”
''将entry参数计算为DBNull,并返回数据类型的默认值
''' 
''泛型类型
“要评估的对象”
''如果值包含数据,则返回铸造的值,否则返回类型的默认值
公共共享函数CheckNull(Of T)(ByVal值作为对象)作为T
若值为Nothing或LSE System.Convert.IsDBNull(值),则
如果GetType(T)=GetType(String),则
返回DirectCast(DirectCast(String.Empty,Object),T)
如果结束
其他的
返回DirectCast(值,T)
如果结束
端函数

我认为您的问题就在这里,row.Item(elem.Key),elem.Key不存在,正是它引发了null异常。您可以通过检查row.Table.Columns.Contains(elem.key)来检查该列。

正如其他人所建议的,调用堆栈中的行号(尽管在构建之间是一致的)总是指向错误的行。函数参数(
)实际上是空值。。谜团已经解决。

任何关于
\u typeProperties
的多线程问题?@jefferson:设计上应该没有(因为包含的对象只有UI线程知道)。此外,我检查了Minidump,以确保没有其他线程在该代码附近(这意味着没有其他线程甚至有发生异常的类的实例)。您能“几天后”在您的机器上复制它吗?或者它只发生在客户的机器上?它只发生在客户的一台特定机器上。虽然这段代码也经常被执行,但在调试过程中我一直无法重现它。我没有尝试在没有调试器或调试器处于发布模式(没有时间)的情况下在我的计算机上复制它代码只有在重现问题时才起作用……当样本从未实际抛出NRE时,检查样本是否存在可能的NRE是毫无价值的……那么为什么这会导致数据中出现异常。添加?读取略有错误。是否有可能另一个线程正在编辑
\u typeProperties
?仅仅因为另一个线程不在同一个代码块中,并不意味着所使用的某个对象没有被触碰——您没有指出后者。关注的不是你写信的对象,而是你阅读的对象;没有其他线程可以访问此线程所在的对象touching@user2517183:那根本不是真的。值可以为null(无)。例如,给定一本
词典
dict.Add(“empty”,Nothing)
是完全合法的。不,我确信异常发生在that@Andreas编译器优化可能在这里发挥作用,我看到它给出了错误的行号。我觉得这就是这里发生的事情,我会检查并确保列存在,看看发生了什么。你说得对。考虑到这样的问题,我已经修改了代码,每行插入一个try/catch块;但是还没有把它推出给客户。第一个验证(typeProperties没有空值或空值)
    ''' <summary>
    ''' Evaluates the entry parameter to <c>DBNull</c>, and returns the default value of data type
    ''' </summary>
    ''' <typeparam name="T">Generic Type</typeparam>
    ''' <param name="Value">Object to evaluate</param>
    ''' <returns>If Value contains data, returns the value casted, otherwise returns the default value of type</returns>
    Public Shared Function CheckNull(Of T)(ByVal Value As Object) As T
        If Value Is Nothing OrElse System.Convert.IsDBNull(Value) Then
            If GetType(T) = GetType(String) Then
                Return DirectCast(DirectCast(String.Empty, Object), T)
            End If
        Else
            Return DirectCast(Value, T)
        End If
    End Function