【问题标题】:Check if WMI ManagementObject query is Nothing instead of using a Try/Catch?检查 WMI ManagementObject 查询是否为 Nothing 而不是使用 Try/Catch?
【发布时间】:2018-05-15 13:44:25
【问题描述】:

在我的程序中,我使用 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 ...:(

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

【问题讨论】:

  • This link 解释了info(strID) 在做什么。
  • Win32_Processor 是 Caption 属性发生错误的实际类吗?或者这只是一个例子?
  • 就我所见,问题不在于任何特定的Win32 类,而在于每个Win32 类的一些 类属性。例如,大约 30% 的 these 属性会导致异常。

标签: .net vb.net wmi


【解决方案1】:

根据您的描述,虽然属性名称可能被列为给定 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 类找不到匹配的属性名称,它将引发“未找到”错误。

【讨论】:

  • 谢谢!这对我很有用,并且大大加快了我的代码速度。我将不得不真正深入研究该文档,以确保我完全了解正在发生的事情,因为我现在还不是 100%。
  • @JonasZebari,我添加了一些信息,可以帮助您使用这种技术感到更舒适。我很高兴它加快了你的代码速度,因为这增加了传统观念的可信度,即抛出和处理错误比一开始就避免错误更昂贵。
【解决方案2】:

我强烈怀疑问题是这个表达式导致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

【讨论】:

  • 我尝试用这段代码替换我的 TryQuery 子程序,当它遇到以前给我异常的查询时,它给了我System.Management.ManagementException: 'Not found '。知道这意味着什么吗?
  • 如果意味着您必须使用 TryCatch,因为管理对象无法让您进行优雅的查找。
  • 为了澄清,它在Dim result = info(strID)这一行给了我这个例外
  • 那很不幸!我将暂时保留这个问题,看看是否有其他人想用他们的 VB 技能来为我们增光添彩。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-08
  • 2017-02-06
  • 2011-01-29
  • 2021-12-31
  • 1970-01-01
  • 2010-11-04
相关资源
最近更新 更多