如何正确处理系统异常?

问题描述:

我遇到了异常处理问题。具体来说,我从进程标识符(PID)创建一个System.Diagnostic.Process对象,然后使用它来执行我的算法。我注意到这个类在访问不同的属性时抛出了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引发,而不是通过访问进程实例;我只需要处理由mWindowProcess引发的异常。

当然我需要一个大的try/catch语句,因为变量mWindowProcess的使用是非常密集

这到底是怎么正确解决?

使用两个独立的try/catch块。每个块处理相同的异常不同。

您可以使用两个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; } 
+0

额外的catch {throw {throw; }'? AFAIK省略,不会改变代码的行为。 – 2010-09-13 17:34:05

+1

重点不在于纠正代码。这是关于显示可以有两个try-catch语句。 – Zafer 2010-09-13 20:44:25

你可以在每次调用前检查Process.HasExited并确定做什么,如果进程已经在该点退出。目前还不清楚是否有系统的方法来处理您的应用程序。不幸的是,您仍然需要检查异常,因为进程可能会在查询调用和Process类的使用之间终止。不幸的是,InvalidOperationException被使用,因为这通常用于指示不可恢复的损坏状态。

不幸的是,正确的做法是,在每个您希望处理错误的特定调用中尝试一下。如果你想退出更大的使用块,然后你可以把你的自定义异常更表示真正的失败的一个选项,以清理它(ProcessTerminatedException,例如。):

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。您可以为可能失败的其他方法/属性创建额外的包装器。

我找到了一个可能的答案。实际上,这解决方案是意外不亚于明显...

这是Exception文档的报价:

异常包括许多帮助识别代码位置,类型,帮助文件的属性,以及例外的原因: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; 
} 

这工作我的代码,直到代码只能访问一个流程实例(mWindowProcess);在多个进程变量(与mWindowProcess不直接相关)引发这些异常的情况下,应该捕获它们,并使用Exception.Data字典来通知不同的情况。

Exception类对异常识别具有非常有效的控制。

+0

如果除Project以外的任何类引发异常,例如在其实现中使用的内部帮助器类,则这将不起作用。依靠TargetSite进行过滤是一个糟糕的主意,因为异常的确切目标站点是可以轻松更改的实现细节。 – 2010-09-14 13:45:52

+0

正确,所以它“有效”,因为流程实施是正确的。这是否合理?如果是这样,这是一个很好的尝试 - 所有模式... – Luca 2010-09-14 16:44:18