Как правильно обрабатывать системные исключения? - PullRequest
0 голосов
/ 13 сентября 2010

У меня проблемы с обработкой исключений. В частности, я создаю объект System.Diagnostic.Process из идентификатора процесса (PID), а затем использую его для выполнения своего алгоритма. Я заметил, что этот класс генерирует исключения InvalidOperation и ArgumentException при доступе к различным свойствам, потому что процесс уже завершился, когда я обращаюсь к экземпляру Process.

Однако алгоритм использует другую функцию, которая выдает те же исключения. Следующий код - тот, который поднял проблему:

XmlWindow mWindow = new XmlWindow(new IntPtr(args.Message.GetContent<Int64>()));
Process mWindowProcess = mWindow.GetProcess();
XmlProcessInstance mWindowProcessInstance = null;
XmlProcessLayout pLayout = null;

Log(mWindow);

lock (mCoreData.ProcessList) {
    try {
        // Ensure matching XmlProcess
        mCoreData.ProcessList.EnsureProcessManagement(mWindowProcess);
    } catch (System.ComponentModel.Win32Exception eWin32Exception) {
        sLog.WarnFormat("Unable to manage window creation ({0}, error code {1}).", eWin32Exception.Message, eWin32Exception.NativeErrorCode);
        break;
    }
}

lock (mCoreData.LayoutList) {
    // Unmanaged process?
    if (mCoreData.LayoutList.IsManagedProcessInstance(mWindowProcess) == false) {
        lock (mCoreData.UnmanagedLayout) {
            // Force process management
            if ((mWindowProcessInstance = mCoreData.UnmanagedLayout.GetProcessInstance((uint)mWindowProcess.Id)) == null) {
                mWindowProcessInstance = mCoreData.UnmanagedLayout.ManageProcessInstance((uint)mWindowProcess.Id, mCoreData.ProcessList);
                sLog.DebugFormat("Layout \"{0}\" will manage explictly the process \"{1}\" ({2}).", mCoreData.UnmanagedLayout.Name, mWindowProcessInstance.ApplicationName, mWindowProcessInstance.InstanceId);
            }
        }
    } else {
        // Find the (managed) process instance
        mWindowProcessInstance = mCoreData.LayoutList.GetProcessInstance((uint)mWindowProcess.Id);
    }
}

Log(mWindowProcessInstance);

// Ensure window match
mWindowProcessInstance.ProcessAssociation.AssociatedItem.LearnWindowMatching(mWindow);
// Register process instance window
mWindowProcessInstance.LearnWindowTemplating(mWindow);
mWindowProcessInstance.Windows.Add(mWindow);
// Apply window template (if any)
mWindowProcessInstance.ApplyTemplateWindow(mWindow);

Проблема заключается в том, как управлять исключением InvalidOperationException. Приведенный выше код не работает, поскольку исключение может быть вызвано SomeFunction вместо обращения к экземпляру Process ; Мне нужно обрабатывать только те исключения, которые выдает mWindowProcess .

Конечно, мне нужен большой оператор try / catch, потому что использование переменной mWindowProcess очень интенсивно

Как это можно решить правильно?

Ответы [ 4 ]

2 голосов
/ 13 сентября 2010

Вы можете использовать два блока try-catch.

Process p = Process.GetProcessById(pid);
try {
    SomeFunction(); // could throw InvalidOperationException
} catch (InvalidOperationException) {  } catch { throw; }
try {
    if (p.Id == 1234) { ... } // could throw InvalidOPerationException!
} catch (InvalidOperationException) {  } catch { throw; }
1 голос
/ 13 сентября 2010

Вы можете проверить Process.HasExited перед каждым вызовом и определить, что делать, если процесс завершился в этот момент.Неясно, есть ли систематический способ справиться с этим для вашего приложения.К сожалению, вам все еще нужно проверить исключение, поскольку процесс может завершиться между вызовом запроса и использованием класса Process.К сожалению, InvalidOperationException использовался, поскольку он часто используется для обозначения неисправимого поврежденного состояния.

Правильный способ сделать это, к сожалению, поставить попытку перехвата каждого конкретного вызова, для которого вы хотите обработатьошибка.Если вы хотите выйти из более крупного блока использования, вы можете затем создать свое собственное пользовательское исключение, которое больше указывает на истинный сбой (например, ProcessTerminationException.) Один из способов исправить это:

    public static int SafeGetId(this Process process)
    {
        if (process == null) throw new ArgumentNullException("process");

        try
        {
            return process.Id;
        }
        catch (InvalidOperationException ex)
        {
            //Do special logic, such as wrap in a custom ProcessTerminatedException
            throw;
        }
    }

Теперь выВы можете вызывать SafeGetId () везде, где вы ранее обращались к Id.Вы можете создать дополнительные оболочки для других методов / свойств, которые могут не работать.

1 голос
/ 13 сентября 2010

Используйте два отдельных блока try / catch.Каждый блок по-разному обрабатывает одно и то же исключение.

0 голосов
/ 13 сентября 2010

Я нашел возможный ответ. По сути, это решение было неожиданным и очевидным ...

Это цитата из Исключения документации:

Исключение включает ряд свойств, которые помогают определить местоположение кода, тип, файл справки и причину исключения: StackTrace, InnerException, Message, HelpLink, HResult, Source, TargetSite и Data.

Перечисленные свойства исключений действительно помогают перехватывать исключения. В моем случае допустимо перехватывать только те исключения, которые выдает класс Process. Итак, я полагаю, этот код является правильным способом фильтрации исключений:

try {
     ....
} catch (InvalidOperationException eInvalidOperationException) {
    if (eInvalidOperationException.TargetSite.DeclaringType == typeof(System.Diagnostics.Process)) {
        // Exception when accessing mWindowProcess
    } else
        throw;
} catch (ArgumentException eArgumentException) {
    if (eArgumentException.TargetSite.DeclaringType == typeof(System.Diagnostics.Process)) {
        // Exception when accessing mWindowProcess
    } else
        throw;
}

Это работает для моего кода, пока код не получит доступ только к одному экземпляру Process ( mWindowProcess ); в случае, если несколько переменных Process (напрямую не связанных с mWindowProcess ) выдают эти исключения, они должны быть перехвачены и использовать словарь Exception.Data для уведомления о другой ситуации.

Класс Exception обладает очень эффективным контролем распознавания исключений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...