如何正确处理系统异常?
我遇到了异常处理问题。具体来说,我从进程标识符(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; }
你可以在每次调用前检查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类对异常识别具有非常有效的控制。
如果除Project以外的任何类引发异常,例如在其实现中使用的内部帮助器类,则这将不起作用。依靠TargetSite进行过滤是一个糟糕的主意,因为异常的确切目标站点是可以轻松更改的实现细节。 – 2010-09-14 13:45:52
正确,所以它“有效”,因为流程实施是正确的。这是否合理?如果是这样,这是一个很好的尝试 - 所有模式... – Luca 2010-09-14 16:44:18
额外的catch {throw {throw; }'? AFAIK省略,不会改变代码的行为。 – 2010-09-13 17:34:05
重点不在于纠正代码。这是关于显示可以有两个try-catch语句。 – Zafer 2010-09-13 20:44:25