欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#如何正確實(shí)現(xiàn)一個(gè)自定義異常Exception

 更新時(shí)間:2023年09月04日 09:01:59   作者:Agile.Zhou  
這篇文章主要為大家詳細(xì)介紹了C#如何正確實(shí)現(xiàn)一個(gè)自定義異常Exception,文中的示例代碼簡(jiǎn)潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

最近在公司的項(xiàng)目中,編寫(xiě)了幾個(gè)自定義的 Exception 類(lèi)。提交 PR 的時(shí)候,sonarqube 提示這幾個(gè)自定義異常不符合 ISerializable patten. 花了點(diǎn)時(shí)間稍微研究了一下,把這個(gè)問(wèn)題解了。今天在此記錄一下,可能大家都會(huì)幫助到大家。

自定義異常

編寫(xiě)一個(gè)自定義的異常,繼承自 Exception,其中定義一個(gè) ErrorCode 來(lái)存儲(chǔ)異常編號(hào)。平平無(wú)奇的一個(gè)類(lèi),太常見(jiàn)了。大家覺(jué)得有沒(méi)有什么問(wèn)題?

    [Serializable]
    public class MyException : Exception
    {
        public string ErrorCode { get;}
        public MyException(string message, string errorCode) : base(message)
        {
            ErrorCode = errorCode;
        }
    }

如我們對(duì)這個(gè)異常編寫(xiě)一個(gè)簡(jiǎn)單的單元測(cè)試。步驟如下:

        [TestMethod()]
        public void MyExceptionTest()
        {
            // arrange
            var orignalException = new MyException("Hi", "1000");
            var bf = new BinaryFormatter();
            var ms = new MemoryStream();
            // act
            bf.Serialize(ms, orignalException);
            ms.Seek(0, 0);
            var newException = bf.Deserialize(ms) as MyException;
            // assert
            Assert.AreEqual(orignalException.Message, newException.Message);
            Assert.AreEqual(orignalException.ErrorCode, newException.ErrorCode);
        }

這個(gè)測(cè)試主要是對(duì)一個(gè) MyException 的實(shí)例使用 BinaryFormatter 進(jìn)行序列化,然后反序列化成一個(gè)新的對(duì)象。將新舊兩個(gè)對(duì)象的 ErrorCode 跟 Message 字段進(jìn)行斷言,也很簡(jiǎn)單。

讓我們運(yùn)行一下這個(gè)測(cè)試,很可惜失敗了。測(cè)試用例直接拋了一個(gè)異常,大概是說(shuō)找不到序列化構(gòu)造器。

Designing Custom Exceptions Guideline

簡(jiǎn)單的搜索了一下,發(fā)現(xiàn)微軟有對(duì)于自定義 Exception 的Designing Custom Exceptions。

總結(jié)一下大概有以下幾點(diǎn):

  • 一定要從 System.Exception 或其他常見(jiàn)基本異常之一派生異常。
  • 異常類(lèi)名稱一定要以后綴 Exception 結(jié)尾。
  • 應(yīng)使異??尚蛄谢?。 異常必須可序列化才能跨越應(yīng)用程序域和遠(yuǎn)程處理邊界正確工作。
  • 一定要在所有異常上都提供(至少是這樣)下列常見(jiàn)構(gòu)造函數(shù)。 確保參數(shù)的名稱和類(lèi)型與在下面的代碼示例中使用的那些相同。
public class NewException : BaseException, ISerializable
{
    public NewException()
    {
        // Add implementation.
    }
    public NewException(string message)
    {
        // Add implementation.
    }
    public NewException(string message, Exception inner)
    {
        // Add implementation.
    }
    // This constructor is needed for serialization.
   protected NewException(SerializationInfo info, StreamingContext context)
   {
        // Add implementation.
   }
}

按照上面的 guideline 重新改一下我們的 MyException,主要是添加了幾個(gè)構(gòu)造器。修改后的代碼如下:

    [Serializable]
    public class MyException : Exception
    {
        public string ErrorCode { get; }
        public MyException()
        {
        }
        public MyException(string message, string errorCode) : base(message)
        {
            ErrorCode = errorCode;
        }
        public MyException(string message, Exception inner): base(message, inner)
        {
        }
        protected MyException(SerializationInfo info, StreamingContext context)
        {
        }
    }

很可惜按照微軟的 guideline 單元測(cè)試還是沒(méi)通過(guò)。獲取 Message 字段的時(shí)候會(huì)直接 throw 一個(gè) Exception。

那么到底該怎么實(shí)現(xiàn)呢?

正確的方式

我們還是按照微軟 guideline 進(jìn)行編寫(xiě),但是在序列化構(gòu)造器的上調(diào)用 base 的構(gòu)造器。并且 override 基類(lèi)的 GetObjectData 方法。

    [Serializable]
    public class MyException : Exception
    {
        public string ErrorCode { get; }
        public MyException()
        {
        }
        public MyException(string message, string errorCode) : base(message)
        {
            ErrorCode = errorCode;
        }
        public MyException(string message, Exception inner): base(message, inner)
        {
        }
        protected MyException(SerializationInfo info, StreamingContext context): base(info, context)
        {
            // Set the ErrorCode value from info dictionary.
            ErrorCode = info.GetString("ErrorCode");
        }
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (!string.IsNullOrEmpty(ErrorCode))
            {
                // Add the ErrorCode to the SerializationInfo dictionary.
                info.AddValue("ErrorCode", ErrorCode);
            }
            base.GetObjectData(info, context);
        }
    }

在序列化構(gòu)造器里從 SerializationInfo 對(duì)象里恢復(fù) ErrorCode 的值。調(diào)用 base 的構(gòu)造可以確保基類(lèi)的 Message 字段被正確的還原。這里與其說(shuō)是序列化構(gòu)造器不如說(shuō)是反序列化構(gòu)造器,因?yàn)檫@個(gè)構(gòu)造器會(huì)在反序列化恢復(fù)成對(duì)象的時(shí)候被調(diào)用。

   protected MyException(SerializationInfo info, StreamingContext context): base(info, context)
        {
            // Set the ErrorCode value from info dictionary.
            ErrorCode = info.GetString("ErrorCode");
        }

這個(gè) GetObjectData 方法是 ISerializable 接口提供的方法,所以基類(lèi)里肯定有實(shí)現(xiàn)。我們的子類(lèi)需要 override 它。把自己需要序列化的字段添加到 SerializationInfo 對(duì)象中,這樣在上面反序列化的時(shí)候確保可以把字段的值給恢復(fù)回來(lái)。記住不要忘記調(diào)用 base.GetObjectData(info, context), 確?;?lèi)的字段數(shù)據(jù)能正確的被序列化。

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (!string.IsNullOrEmpty(ErrorCode))
            {
                // Add the ErrorCode to the SerializationInfo dictionary.
                info.AddValue("ErrorCode", ErrorCode);
            }
            base.GetObjectData(info, context);
        }

再次運(yùn)行單元測(cè)試,這次順利的通過(guò)了,說(shuō)明 Message 跟 ErrorCode 字段在反序列化后成功的被恢復(fù)了。

總結(jié)

自定義異常是大家日常編碼過(guò)程中非常常見(jiàn)的操作。但是看來(lái)要寫(xiě)好一個(gè)自定義異常類(lèi)也不是那么簡(jiǎn)單??偨Y(jié)一下需要注意以下幾點(diǎn):

  • 添加 [Serializable] Attribute
  • 遵守微軟的 guideline,特別是構(gòu)造器部分 Designing Custom Exceptions Guideline
  • 在序列化構(gòu)造器對(duì)字段值進(jìn)行恢復(fù),不要忘記調(diào)用基類(lèi)的序列化構(gòu)造器
  • 重寫(xiě) GetObjectData 方法,把需要序列化的字段添加到 SerializationInfo 對(duì)象上,同樣不要忘記調(diào)用基類(lèi)的 GetObjectData這個(gè)問(wèn)題雖然在自定義 Exception 上暴露出來(lái),其實(shí)可以推廣到所有實(shí)現(xiàn) ISerializable 接口的類(lèi)都需要注意 3,4 兩點(diǎn)。

以上就是C#如何正確實(shí)現(xiàn)一個(gè)自定義異常Exception的詳細(xì)內(nèi)容,更多關(guān)于C#自定義異常的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#中使用委托的3種方式代碼示例

    C#中使用委托的3種方式代碼示例

    這篇文章主要介紹了C#中使用委托的3種方式代碼示例,本文直接給出代碼實(shí)例,沒(méi)有相關(guān)的說(shuō)明解釋,需要的朋友可以參考下
    2015-03-03
  • C#中的串口通信SerialPort詳解

    C#中的串口通信SerialPort詳解

    今天這篇文章帶大家學(xué)習(xí)下C#中的串口通訊。在日常的開(kāi)發(fā)工作中,如果工作內(nèi)容是CS方向的同學(xué)應(yīng)該很容易接觸到串口通訊方面的業(yè)務(wù)需求。那么也就很容易想到C#中SerialPort類(lèi),它就是專(zhuān)門(mén)來(lái)處理串口通訊相關(guān)的
    2022-01-01
  • C#獲取路徑的幾種方式實(shí)例分析

    C#獲取路徑的幾種方式實(shí)例分析

    這篇文章主要介紹了C#獲取路徑的幾種方式,實(shí)例分析了C#常用的路徑操作技巧,需要的朋友可以參考下
    2015-06-06
  • C#開(kāi)發(fā)簡(jiǎn)易winform計(jì)算器程序

    C#開(kāi)發(fā)簡(jiǎn)易winform計(jì)算器程序

    這篇文章主要為大家詳細(xì)介紹了C#開(kāi)發(fā)簡(jiǎn)易winform計(jì)算器程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • C# MeasureString測(cè)量字符串函數(shù)的使用方法

    C# MeasureString測(cè)量字符串函數(shù)的使用方法

    這篇文章主要介紹了C# MeasureString測(cè)量字符串函數(shù)的使用方法,需要的朋友可以參考下
    2014-10-10
  • C#通過(guò)chrome插件將HTML網(wǎng)頁(yè)轉(zhuǎn)換為PDF

    C#通過(guò)chrome插件將HTML網(wǎng)頁(yè)轉(zhuǎn)換為PDF

    這篇文章主要介紹了C#通過(guò)chrome插件將HTML網(wǎng)頁(yè)轉(zhuǎn)換為PDF,將HTML網(wǎng)頁(yè)內(nèi)容轉(zhuǎn)換為 PDF 格式能方便文檔的后續(xù)打印、存檔和分享等,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下
    2025-03-03
  • C#在Unity游戲開(kāi)發(fā)中進(jìn)行多線程編程的方法

    C#在Unity游戲開(kāi)發(fā)中進(jìn)行多線程編程的方法

    這篇文章主要介紹了C#在Unity游戲開(kāi)發(fā)中進(jìn)行多線程編程的方法,文中總結(jié)了Unity中使用多線程的幾種方式以及一款多線程插件的介紹,需要的朋友可以參考下
    2016-04-04
  • C#讀取txt文件數(shù)據(jù)的方法實(shí)例

    C#讀取txt文件數(shù)據(jù)的方法實(shí)例

    讀取txt文本數(shù)據(jù)的內(nèi)容,是我們開(kāi)發(fā)中經(jīng)常會(huì)遇到的一個(gè)功能,這篇文章主要給大家介紹了關(guān)于C#讀取txt文件數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下
    2021-05-05
  • C#圖表算法之無(wú)向圖

    C#圖表算法之無(wú)向圖

    這篇文章介紹了C#圖表算法之無(wú)向圖,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • c# 獲得當(dāng)前絕對(duì)路徑的方法(超簡(jiǎn)單)

    c# 獲得當(dāng)前絕對(duì)路徑的方法(超簡(jiǎn)單)

    下面小編就為大家分享一篇c# 獲得當(dāng)前絕對(duì)路徑的方法(超簡(jiǎn)單),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01

最新評(píng)論