Проверьте, является ли запрос WMI ManagementObject Nothing вместо использования Try / Catch? - PullRequest
0 голосов
/ 15 мая 2018

В моей программе я использую интерфейс 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. Любое понимание будет оценено. Спасибо!

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Судя по вашему описанию, кажется, что хотя имя свойства может быть указано как существующее для данного класса 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

Редактировать: Чтобы обеспечить некоторую уверенность в том, что этот метод действителен, вы можете проверить исходный код для индексатора в 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 выдает ошибку «Не найдено», если не может найти подходящее имя свойства.

0 голосов
/ 15 мая 2018

Я сильно подозреваю, что проблема в том, что это выражение приводит к 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...