检查WMI ManagementObject查询是否为Nothing而不是使用Try / Catch?

时间:2018-05-15 13:44:25

标签: .net vb.net wmi

在我的程序中,我使用WMI接口来查询有关运行程序的硬件的大量信息。然后我将这些信息放入一个列表中以帮助稍后显示它,但目前还没有其他更多的信息。到目前为止,这种方法效果很好,但有一个主要问题:有时查询是/返回(不知道哪一个!)Nothing并导致NullReferenceException

现在,很明显我可以将它包装在Try / Catch中,并以我的快乐方式。但是,我想避免这样做,因为我将查询数百位信息,其中数百个可能会导致异常。这只是草率的编程,并且大大减慢了我的程序!

我的问题是:我应该检查哪些内容才能使用If代替Try?我将把我当前的代码放在下面,然后列出我已经尝试过的解决方案。

    Public Shared Function GetSomeInfo() As List(Of String)
        Dim ret As New List(Of String)
        Dim sq As New Management.SelectQuery("Win32_Processor")
        Dim mos As New Management.ManagementObjectSearcher(sq)
        For Each info As Management.ManagementObject In mos.Get()
            ret.Add(TryQuery(info, "Name"))
            ret.Add(TryQuery(info, "Caption")) 'this query may result in Nothing somewhere...
        Next
        Return ret
    End Function

    Private Shared Function TryQuery(ByRef info As 
            Management.ManagementObject, ByVal strID As String) As String
        Try
            Return strID & ": " & info(strID).ToString 'exception obviously thrown here...but WHERE?
        Catch ex As NullReferenceException
            Return String.Empty
        Catch ex As Management.ManagementException
            Return String.Empty
        End Try
    End Function

所以,这就是我尝试使用此Try尝试和解决的问题:

If Not info Is Nothing Then ...仍导致一些未捕获的异常

If Not info(strID) Is Nothing Then ...某处仍然有例外

If Not info.Equals(Nothing) Then ...绝望

If Not Info(strID).ToString Is Nothing ... :(

我根本不知道 where 来检查在WMI查询中抛出此异常。任何见解将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:5)

根据您的描述,虽然属性名称可能会列为给定WMI类的现有名称,但WMI PropertyData项目不适用于给定的属性名称。强制方法应该通过迭代正确的PropertyDataCollection来避免生成“未找到”异常。

Private Shared Function TryQuery(ByRef info As ManagementObject, ByVal strID As String) As String
    Dim ret As String = String.Empty
    Dim propDatas As PropertyDataCollection
    If strID.StartsWith("__") Then
        ' system property, ref: https://msdn.microsoft.com/en-us/library/system.management.managementbaseobject.systemproperties(v=vs.110).aspx
        propDatas = info.SystemProperties
    Else
        ' object properties: ref: https://msdn.microsoft.com/en-us/library/system.management.managementbaseobject.properties(v=vs.110).aspx
        propDatas = info.Properties
    End If
    For Each data As PropertyData In propDatas
        If data.Name.Equals(strID, StringComparison.InvariantCultureIgnoreCase) Then
            ret = If(data.Value, String.Empty).ToString
            Exit For
        End If
    Next
    Return ret
End Function

此外,大多数WMI对象都是Disposable,因此应该进行处理。

Public Shared Function GetSomeInfo() As List(Of String)
    Dim ret As New List(Of String)
    Dim sq As New Management.SelectQuery("Win32_Processor")
    Using mos As New Management.ManagementObjectSearcher(sq)
        Using objects As ManagementObjectCollection = mos.Get
            For Each info As Management.ManagementObject In objects
                Using info
                    ret.Add(TryQuery(info, "Name"))
                    ret.Add(TryQuery(info, "Caption")) 'this query may result in Nothing somewhere...
                End Using
            Next
        End Using
    End Using
    Return ret
End Function

编辑:为了确保此技术有效,您可以检查source code for the indexer on the ManagementBaseObject。此方法调用:

public Object GetPropertyValue(string propertyName)
{ 
    if (null == propertyName)
        throw new ArgumentNullException ("propertyName");

    // Check for system properties
    if (propertyName.StartsWith ("__", StringComparison.Ordinal))
        return SystemProperties[propertyName].Value;
    else
        return Properties[propertyName].Value;
}

您可以看到,这会检索与我提供的代码类似的属性。问题是,如果ProdertyDataCollection类找不到匹配的属性名称,则会抛出“Not Found”错误。

答案 1 :(得分:-1)

我强烈怀疑问题是这个表达式导致Nothing

info(strID)

到目前为止,检查该表达式结果的现有代码中的每个地方都只在调用.ToString()之后才这样做,即:info(strID).ToString()。因此,它尝试在Nothing对象上调用方法。你可以像这样解决它:

Private Shared Function TryQuery(ByRef info As 
        Management.ManagementObject, ByVal strID As String) As String

    If info Is Nothing OrElse strID Is Nothing Then Return String.Empty
    Dim result = info(strID)
    If result Is Nothing Then Return String.Empty
    Return String.Format("{0}: {1}", strID, result)
End Function