国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

從AggregateException看異常類的設計

2019-11-17 03:07:34
字體:
來源:轉載
供稿:網友

從AggregateException看異常類的設計

異常是程序在有bug時最直觀的表現形式,不擔心有bug存在,而擔心bug埋沒在大堆的代碼中而發現不了。

這篇隨筆簡單談談從AggregateException類源碼(http://www.PRojky.com/dotnet/4.5.1/System/AggregateException.cs.html)中窺出的.NET Framework類庫設計的方式。

總結有以下幾點:

1、特性的使用:DebuggerDisplayAttribute,SerializableAttribute

2、只讀屬性的運用

3、簡單的隊列算法

AggregateException主要用在TPL庫中,在等待時發生異常的Task可能不止一個,所以,設計通過InnerExceptions屬性訪問所有的異常。需要特別注意的是,Exception對象本身有一個InnerException屬性,是單數的,少了個s,最多只能記錄一個異常。先來看看它的一個典型用法:

int[] locations = GetCacheLocations();var readCacheTasks = new Task<CacheItem>[locations.Length];for (int i = 0; i < locations.Length; i++) {    int location = locations[i];    readCacheTasks[i] = new Task<CacheItem>(ReadDistributeCache, location);    readCacheTasks[i].Start();}try {    Task.WaitAll(readCacheTasks);    for(int i = 0; i < locations.Length; i++){        ProcessCacheItem(readCacheTasks[i].Result, i);    }} catch (AggregateException ae) {    ae.Handle(e => {        return e is NotFoundException;    });    //throw ae.Flatten();}

這段代碼中,如果讀取分布式緩存的多個任務發生了異常,也能及時確定是否存在一個bug。

從AggregateException的源碼看,只有兩個特性聲明在該類上,

[Serializable][DebuggerDisplay("Count = {InnerExceptionCount}")]public class AggregateException : Exception {    private int InnerExceptionCount{        get{            return InnerExceptions.Count;        }    }        ......}

DebuggerDisplayAttribute特性讓我們在下斷點調試時,鼠標位置在該類上出現的提示。例如,包含了3個內部異常,那么在斷點提示是會是“Count = 3”,這里訪問了私有的屬性,不一定要私有的,但私有的成員在寫代碼時不會出現在代碼提示中,減少了干擾。

SerializableAttribute特性讓該類支持序列化,比如序列化成xml文件、流、json等格式,再反序列化得到該類對象。僅僅聲明該屬性是不夠的,還添加實現兩個成員,一是在序列化過程中,要往結果中存什么,GetObjectData方法,二是支持反序列化的構造函數。

public override void GetObjectData(SerializationInfo info, StreamingContext context){    base.GetObjectData(info, context);    Exception[] innerExceptions = new Exception[m_innerExceptions.Count];    m_innerExceptions.CopyTo(innerExceptions, 0);    info.AddValue("InnerExceptions", innerExceptions, typeof(Exception[]));}protected AggregateException(SerializationInfo info, StreamingContext context) : base(info, context){    Exception[] innerExceptions = info.GetValue("InnerExceptions", typeof(Exception[])) as Exception[];    m_innerExceptions = new ReadOnlyCollection<Exception>(innerExceptions);}

字符串“InnerExceptions”只是一個名字而已,相當于一個key,不同的屬性,key必須不同,同時,還得避免繼承可能導致的key重復問題。

大部分情況下,使用AggregateException都是訪問它的InnerExceptions屬性,

private ReadOnlyCollection<Exception> m_innerExceptions; // Complete set of exceptions.public ReadOnlyCollection<Exception> InnerExceptions{    get { return m_innerExceptions; }}private AggregateException(string message, IList<Exception> innerExceptions)            : base(message, innerExceptions != null && innerExceptions.Count > 0 ? innerExceptions[0] : null){    Exception[] exceptionsCopy = new Exception[innerExceptions.Count];    for (int i = 0; i < exceptionsCopy.Length; i++){        exceptionsCopy[i] = innerExceptions[i];        if (exceptionsCopy[i] == null){            throw new ArgumentException(Environment.GetResourceString("AggregateException_ctor_InnerExceptionNull"));        }    }    m_innerExceptions = new ReadOnlyCollection<Exception>(exceptionsCopy);}

它的InnerExceptions屬性是只讀的,避免外部訪問修改,而且在構造該AggregateException對象實例時,對參數檢驗和直接的淺拷貝,盡量使整個過程只在返回時修改類的狀態,一般情況下,可以認為該過程沒有副作用。

如果你仔細想想,可能在InnerExceptions中,也存在AggregateException對象,所以,專門提供了一個Flatten方法,來提取層級中所有的非AggregateException對象到一個ReadOnlyCollection<Exception>對象中,字面意思理解就是扁平化。

public AggregateException Flatten(){    // Initialize a collection to contain the flattened exceptions.    List<Exception> flattenedExceptions = new List<Exception>();    // Create a list to remember all aggregates to be flattened, this will be accessed like a FIFO queue    List<AggregateException> exceptionsToFlatten = new List<AggregateException>();    exceptionsToFlatten.Add(this);    int nDequeueIndex = 0;    // Continue removing and recursively flattening exceptions, until there are no more.    while (exceptionsToFlatten.Count > nDequeueIndex){        // dequeue one from exceptionsToFlatten        IList<Exception> currentInnerExceptions = exceptionsToFlatten[nDequeueIndex++].InnerExceptions;        for (int i = 0; i < currentInnerExceptions.Count; i++){            Exception currentInnerException = currentInnerExceptions[i];            if (currentInnerException == null){                continue;            }            AggregateException currentInnerAsAggregate = currentInnerException as AggregateException;            // If this exception is an aggregate, keep it around for later.  Otherwise,            // simply add it to the list of flattened exceptions to be returned.            if (currentInnerAsAggregate != null){                exceptionsToFlatten.Add(currentInnerAsAggregate);            }            else{                flattenedExceptions.Add(currentInnerException);            }        }    }    return new AggregateException(Message, flattenedExceptions);}

這段代碼實現了一個FIFO隊列,但并不是傳統意義上的隊列,沒有出隊列,只有入隊列,通過一個遞增索引記錄處理到哪一個元素了。仔細琢磨,設計得還是挺不錯的,簡單實用。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 饶河县| 大足县| 南乐县| 和田市| 宣威市| 阿克陶县| 永修县| 德令哈市| 双城市| 临武县| 康定县| 宝兴县| 汕头市| 永善县| 钦州市| 枝江市| 浮梁县| 夏津县| 焦作市| 建平县| 波密县| 沭阳县| 天全县| 平乡县| 色达县| 西城区| 上虞市| 沾化县| 盐边县| 高陵县| 安宁市| 贵南县| 乳源| 临洮县| 贵定县| 景德镇市| 万山特区| 邯郸县| 清徐县| 临西县| 光山县|