最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

自定義異常

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

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

如我們對這個(gè)異常編寫一個(gè)簡單的單元測試。步驟如下:

        [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è)測試主要是對一個(gè) MyException 的實(shí)例使用 BinaryFormatter 進(jìn)行序列化,然后反序列化成一個(gè)新的對象。將新舊兩個(gè)對象的 ErrorCode 跟 Message 字段進(jìn)行斷言,也很簡單。

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

Designing Custom Exceptions Guideline

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

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

  • 一定要從 System.Exception 或其他常見基本異常之一派生異常。
  • 異常類名稱一定要以后綴 Exception 結(jié)尾。
  • 應(yīng)使異常可序列化。 異常必須可序列化才能跨越應(yīng)用程序域和遠(yuǎn)程處理邊界正確工作。
  • 一定要在所有異常上都提供(至少是這樣)下列常見構(gòu)造函數(shù)。 確保參數(shù)的名稱和類型與在下面的代碼示例中使用的那些相同。
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 單元測試還是沒通過。獲取 Message 字段的時(shí)候會(huì)直接 throw 一個(gè) Exception。

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

正確的方式

我們還是按照微軟 guideline 進(jìn)行編寫,但是在序列化構(gòu)造器的上調(diào)用 base 的構(gòu)造器。并且 override 基類的 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 對象里恢復(fù) ErrorCode 的值。調(diào)用 base 的構(gòu)造可以確?;惖?nbsp;Message 字段被正確的還原。這里與其說是序列化構(gòu)造器不如說是反序列化構(gòu)造器,因?yàn)檫@個(gè)構(gòu)造器會(huì)在反序列化恢復(fù)成對象的時(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 接口提供的方法,所以基類里肯定有實(shí)現(xiàn)。我們的子類需要 override 它。把自己需要序列化的字段添加到 SerializationInfo 對象中,這樣在上面反序列化的時(shí)候確??梢园炎侄蔚闹到o恢復(fù)回來。記住不要忘記調(diào)用 base.GetObjectData(info, context), 確?;惖淖侄螖?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)行單元測試,這次順利的通過了,說明 Message 跟 ErrorCode 字段在反序列化后成功的被恢復(fù)了。

總結(jié)

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

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

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

相關(guān)文章

最新評(píng)論

上犹县| 普宁市| 大荔县| 民权县| 佳木斯市| 仲巴县| 江安县| 德兴市| 霍邱县| 玉龙| 北流市| 淅川县| 咸阳市| 正阳县| 兴安盟| 昌平区| 舟山市| 和田市| 墨竹工卡县| 保康县| 卓资县| 龙游县| 新竹市| 来宾市| 探索| 霍林郭勒市| 华阴市| 东明县| 诸暨市| 兴国县| 临沂市| 远安县| 金沙县| 环江| 天祝| 浦县| 安岳县| 云霄县| 桃源县| 达拉特旗| 句容市|