2010-09-13 156 views
0

我遇到了異常處理問題。具體來說,我從進程標識符(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的使用是非常密集

這到底是怎麼正確解決?

回答

1

使用兩個獨立的try/catch塊。每個塊處理相同的異常不同。

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; } 
+0

額外的catch {throw {throw; }'? AFAIK省略,不會改變代碼的行爲。 – 2010-09-13 17:34:05

+1

重點不在於糾正代碼。這是關於顯示可以有兩個try-catch語句。 – Zafer 2010-09-13 20:44:25

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; 
     } 
    } 

現在你可以調用SafeGetId()您以前訪問過的所有ID。您可以爲可能失敗的其他方法/屬性創建額外的包裝器。

0

我找到了一個可能的答案。實際上,這解決方案是意外不亞於明顯...

這是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