我遇到异常处理问题。具体来说,我从进程标识符(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 可以抛出异常,而是访问 Process 实例;我只需要处理 mWindowProcess 抛出的异常。
当然我需要一个很大的try / catch语句,因为变量 mWindowProcess 的使用非常密集
如何正确解决这个问题?
答案 0 :(得分:2)
您可以使用两个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 :(得分:1)
使用两个单独的try / catch块。每个块以不同方式处理相同的异常。
答案 2 :(得分:1)
您可以在每次通话前检查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;
}
}
现在,您可以在以前访问Id的任何地方调用SafeGetId()。您可以为可能失败的其他方法/属性创建其他包装器。
答案 3 :(得分:0)
我找到了一个可能的答案。实际上,这个解决方案出乎意料的那么明显......
这是Exception文档的引用:
异常包括许多属性,这些属性有助于识别代码位置,类型,帮助文件以及异常原因:StackTrace,InnerException,Message,HelpLink,HResult,Source,TargetSite和Data。
列出的Exception属性确实有助于异常捕获。在我的例子中,只捕获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类对异常识别有非常有效的控制。