簡體   English   中英

托管代碼是否應該返回錯誤或將異常拋給非托管代碼?

[英]Should managed code return an error or throw exceptions to unmanaged code?

我將使用COM將使用C#編寫的服務公開給傳統的C ++應用程序。 向非托管客戶端報告錯誤的最佳方法是什么? 拋出異常或只返回錯誤值?

謝謝,斯特凡諾

你應該拋出異常。 框架將異常映射到HRESULTS,而HRESULT是將錯誤返回給COM客戶端的標准方法,因此這是可行的方法。

每個Exception類型都有一個HResult屬性。 當從COM客戶端調用的托管代碼拋出異常時,運行時將HResult傳遞給COM客戶端。 如果需要特定於應用程序的HRESULT代碼,則可以創建自己的自定義異常類型並設置Exception.HResult屬性。

需要注意的一點是,當向COM客戶端拋出異常時,調用堆棧信息將丟失。 因此,在傳播到COM客戶端之前記錄異常是個好主意。

我有時使用的一種技術如下:為COM客戶端顯式實現一個ComVisible接口,用於記錄和重新拋出異常。 COM客戶端使用ComVisible接口在傳播異常之前記錄異常。 .NET客戶端使用具體類,並期望自己安排異常處理。 編寫它有點啰嗦,但在您隨后進行故障排除時可能會有所幫助。

此方法的另一個優點是,您可以根據COM客戶端的COM限制定制API,並為標准.NET客戶端提供更標准的API。 例如,COM客戶端僅限於通過引用傳遞數組,而不支持.NET客戶端通過引用傳遞。

例:

[
ComVisible(true),
GuidAttribute("..."),
Description("...")
]
public interface IMyComVisibleClass
{
    // Text from the Description attribute will be exported to the COM type library.

    [Description("...")]
    MyResult MyMethod(...);

    [Description("...")]
    MyOtherResult MyArrayMethod([In] ref int[] ids,...);
}
...
[
ComVisible(true),
GuidAttribute("..."),
ProgId("..."),
ClassInterface(ClassInterfaceType.None),
Description("...")
]
public class MyComVisibleClass : IMyComVisibleClass
{
    public MyResult MyMethod(...)
    {
        ... implementation without exception handling ...
    }

    public MyOtherResult MyArrayMethod(int[] ids,...)
    {
        ... input parameter does not use ref keyword for .NET clients ...
        ... implementation without exception handling ...
    }

    MyResult IMyComVisibleClass.MyMethod(...)
    {
        // intended for COM clients only
        try
        {
            return this.MyMethod(...);
        }
        catch(Exception ex)
        {
            ... log exception ...
            throw;   // Optionally wrap in a custom exception type
        }
    }

    MyOtherResult IMyComVisibleClass.MyArrayMethod(ref int[] ids, ...)
    {
        // intended for COM clients only
        try
        {
            // Array is passed without ref keyword
            return this.MyArrayMethod(ids, ...);
        }
        catch(Exception ex)
        {
            ... log exception ...
            throw;   // Optionally wrap in a custom exception type
        }
    }

}

如果您的COM應用程序在調用C#服務時支持IErrorInfo接口,並且它是一個完全內部項目,那么拋出異常可能是最好的選擇,因為它捕獲了大部分信息。 但是,COM傳統上依靠HR結果來傳達狀態結果,如果要將服務發布到其他來源可能會更好。

編輯:我更喜歡喬的回答。

我同意其他人的觀點,如果不親密地了解你的項目,這不是一個“是或否”的答案。

這取決於許多因素,例如:

  • 安全性(即您的客戶應該知道您的例外情況)
  • 效率(即處理時間至關重要)
  • 可維護性(即您可以更改舊的C ++代碼來解析異常情況)

這是一篇很好的博客文章,討論了有關異常處理的一些細微之處。

作者建議采用以下兩種方法之一:

或者:

  • 返回錯誤文檔。

要么:

  • 在服務器上記錄有關異常的所有信息。
  • 創建引用記錄信息的新異常。
  • 將新例外發送到客戶端以進行客戶端處理和報告。

就個人而言,我認為你應該避免將C#服務與C ++應用程序緊密結合。 換句話說,編寫C#服務,以便理論上可以被任何消費者使用。 同樣,應編寫C ++代碼,使其不依賴於C#服務的內部工作,因此對異常(或錯誤代碼)的更改或添加不會破壞使用者。

我認為這取決於遺留應用程序的反應方式。 如果它理解錯誤返回值,那么請使用該方法。 如果沒有,那么你將不得不拋出異常並希望它適當地處理它們。

此外,如果它是一個錯誤的引用(例如null引用)或其他嚴重錯誤,我總是會拋出異常。 但是,對於消費者無法事先檢查的事情,應該避免例外情況(例如,空出的搜索不應該拋出異常)。

最好的判斷你是使用例外還是返回值將是你。 “拋出異常”在幾個方面超過了“回歸價值”。 但在某些情況下,返回值就足夠了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM