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

解析C#中斷言與異常的應(yīng)用方式及異常處理的流程控制

 更新時間:2016年01月26日 16:31:03   作者:曹宗穎  
這篇文章主要介紹了C#中斷言與異常的應(yīng)用方式及異常處理的流程控制,一般來說斷言用于修正程序員自己的錯誤而異常用于應(yīng)對程序運行過程中可能出現(xiàn)的錯誤,需要的朋友可以參考下

斷言與異常(Assertion Vs Exception)
在日常編程實踐中,斷言與異常的界限不是很明顯,這也使得它們常常沒有被正確的使用。我也在不斷的與這個模糊的怪獸搏斗,僅寫此文和大家分享一下我的個人看法。我想我們還可以從很多角度來區(qū)別斷言和異常的使用場景,歡迎大家的意見和建議。

異常的使用場景:用于捕獲外部的可能錯誤

斷言的使用場景:用于捕獲內(nèi)部的不可能錯誤

我們可以先仔細分析一下我們在.net中已經(jīng)存在的異常。

  • System.IO.FileLoadException
  • SqlException
  • IOException
  • ServerException

首先,我們先不將它們看成異常,因為我們現(xiàn)在還沒有在異常和斷言之間劃清界限,我們先將它們看成錯誤。

當(dāng)我們在編碼的第一現(xiàn)場考慮到可能會出現(xiàn)文件加載的錯誤或者服務(wù)器錯誤后,我們的第一直覺是這不是我們代碼的問題,這是我們代碼之外的問題。

例如下面這段代碼

public void WriteSnapShot(string fileName, IEnumerable<DbItem> items)
    {
      string format = "{0}\t{1}\t{2}\t{3}\t{4}\t{5}";
      using (FileStream fs = new FileStream(fileName, FileMode.Create))
      {
        using (StreamWriter sw = new StreamWriter(fs, Encoding.Unicode))
        {
           ...
          foreach (var item in items)
          {
            sw.WriteLine(string.Format(format, new object[]{
              item.dealMan,
              item.version,
              item.priority,
              item.bugStatus,
              item.bugNum,
              item.description}));
          }
          sw.Flush();
        }
      }
    }

上面的代碼在寫入文件,很顯然會導(dǎo)致IOException。稍微有經(jīng)驗的程序員都會考慮到IO上可能出問題,那我們應(yīng)該如何處理這個問題呢?在這個上下文中,我們別無它法,只能讓這個錯誤繼續(xù)往上拋,通知上面一層的調(diào)用者,有一個錯誤發(fā)生了,至于上一層調(diào)用者會如何處理,不是這個函數(shù)要考慮的問題。但在這個函數(shù)中,要記得一點,將當(dāng)前函數(shù)中所占用的資源釋放了。因此,當(dāng)我們不能控制的外部錯誤出現(xiàn)時,我們可以將其作為異常往上拋,這時,我們該使用異常。

現(xiàn)在再來看看斷言,我們還是以下面的一段代碼為例子。

public Entities.SimpleBugInfo GetSimpleBugInfo(string bugNum)
    {

      var selector = DependencyFactory.Resolve<ISelector>();

      var list = selector.Return<Entities.SimpleBugInfo>(
        reader => new Entities.SimpleBugInfo
        {
          bugNum = reader["bugNum"].ToString(),
          dealMan = reader["dealMan"].ToString(),
          description = reader["description"].ToString(),
          size = Convert.ToInt32(reader["size"]),
          fired = Convert.ToInt32(reader["fired"]),
        },
        "select * from bugInfo",
        new WhereClause(bugNum, "bugNum"));

      Trace.Assert(list != null);
      
      if (list.Count == 0)
        return null;
      else
        return list[0];

    }

當(dāng)我貼出這段代碼時,心情有些坎坷,因為我本人在這里也糾結(jié)了很久,這也是我一直沒有將斷言和異常劃清界線的原因之一。

首先我們來回顧一下之前定義的斷言使用場景:內(nèi)部不可能發(fā)生的錯誤。

selector.Return這段代碼是不是內(nèi)部代碼?如果我們能夠修改Return中的代碼,說明它是內(nèi)部代碼;反之,說明它是外部代碼。對于內(nèi)部代碼,我們可以用斷言來保護其邏輯的不變性,當(dāng)斷言被觸發(fā)時,我們就可以確信是內(nèi)部代碼的錯誤,我們應(yīng)該立即修復(fù)。

再糾結(jié)一下,假設(shè)Return是外部代碼,我們沒有辦法去修改它。那么上面的代碼可以有兩種寫法(如果你有更多的想法,請賜教)。

第一種,直接拋出異常。

If(list == null)
{
  throw new NullReferenceException();
}

第二種,調(diào)整代碼。

if(list == null || list.Count == 0)
{
  return null;
}
else
{
  return list[0];
}

當(dāng)然,還有一種就是什么也不做,讓代碼執(zhí)行下去直至系統(tǒng)為你拋出空引用錯誤。但這種做法違背了防卸性編程的原則,我們總是應(yīng)行盡早或離錯誤的發(fā)生地最近的地方處理錯誤,避免錯誤數(shù)據(jù)流向系統(tǒng)的其它地方,產(chǎn)生更加嚴重的錯誤。

總結(jié)

對異常或斷言的使用取決于你要防卸的是一個內(nèi)部錯誤還是外部錯誤以及你認為它是一個內(nèi)部錯誤或外部錯誤。如果你決定防卸一個內(nèi)部錯誤,那請果斷使用斷言,反之,請使用異常。

異常處理
異常處理對于流程的控制,就像拋出與捕獲一樣分為兩個方面:

如果錯誤(或某種情況)發(fā)生,是否允許程序的控制流繼續(xù)執(zhí)行下去(異常的拋出)
如果當(dāng)前有異常發(fā)生,當(dāng)前的代碼是否有機會讓程序的控制流進入到一個合理的狀態(tài)(異常的捕獲)
我認為可以用以上兩條,作為判斷異常處理的準(zhǔn)繩。其實大家現(xiàn)在應(yīng)該可以發(fā)現(xiàn),這個所謂的準(zhǔn)繩的著重點在于異常對于流程的影響,而不再是在什么情況下才使用異常。

對于流程控制,最直接的莫過于下面這段代碼

try
          {
            foreach (var lockGroup in lockGroups)
            {
 
              ...
 
              foreach (var newlock in lockGroup.ToArray())
              {
                ...
                if (diningBlocks.Exists(n => testLockRange.IsOverlapped(n.StartTime, n.EndTime)))
                {
                  status = LockStatus.InResourceBlock;
                  throw new LockException();
                }
 
                var diningAvail = availabilities.Find(n => n.Time == newlock.StartTime.TimeOfDay);
                if (diningAvail == null)
                {
                  status = LockStatus.Failed;
                  throw new LockException();
                }
 
                ...
                 
                if (newLockQuantity > diningAvail.MaxAvail && !canOverrideLock.AllowOverBook)
                {
                  status = LockStatus.Override;
                  throw new LockException();
                }
                else if (newLockQuantity + reservedQuantity + currentLockedAvail > diningAvail.MaxAvail && !canOverrideLock.AllowOverBook)
                {
                  status = LockStatus.Override;
                  throw new LockException();
                }
 
                ...
              }
            }
          }
          catch (LockException)
          {
            return new DiningLock[] { };
          }

在上面的代碼中,有兩層for循環(huán),當(dāng)最內(nèi)層出現(xiàn)某種情況時,要求停止整個for循環(huán)的執(zhí)行,顯然用兩個break是不行的,還得加入一個輔助變量。

但是,如果用異常,這個處理就簡單多了??梢灾苯釉谧顑?nèi)層的拋出異常,在最外層(或是流程控制需要的地方)捕獲異常。

在上面的代碼中,異常處理起到了流程控制的作用,而不僅僅傳遞錯誤信息,對代碼的簡化做出了貢獻。

相關(guān)文章

  • Unity實現(xiàn)10天簽到系統(tǒng)

    Unity實現(xiàn)10天簽到系統(tǒng)

    這篇文章主要為大家詳細介紹了Unity實現(xiàn)10天簽到系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • C#中LINQ?to?DataSet操作及DataTable與LINQ相互轉(zhuǎn)換

    C#中LINQ?to?DataSet操作及DataTable與LINQ相互轉(zhuǎn)換

    這篇文章介紹了C#中LINQ?to?DataSet操作及DataTable與LINQ相互轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • C#反射使用方法過程及步驟

    C#反射使用方法過程及步驟

    這篇文章主要為大家詳細介紹了C#反射使用方法過程及步驟,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C#實現(xiàn)將javascript文件編譯成dll文件的方法

    C#實現(xiàn)將javascript文件編譯成dll文件的方法

    這篇文章主要介紹了C#實現(xiàn)將javascript文件編譯成dll文件的方法,涉及C#編譯生成dll動態(tài)鏈接庫文件的實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • C#之線程同步Mutex類方式

    C#之線程同步Mutex類方式

    這篇文章主要介紹了C#之線程同步Mutex類方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • c# 給pdf添加數(shù)字簽名的步驟

    c# 給pdf添加數(shù)字簽名的步驟

    這篇文章主要介紹了c# 給pdf添加數(shù)字簽名的步驟,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2020-12-12
  • C#實現(xiàn)合并及拆分PDF文件的方法

    C#實現(xiàn)合并及拆分PDF文件的方法

    這篇文章主要為大家詳細介紹了C#合并及拆分PDF文件的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C#中foreach語句使用break暫停遍歷的方法

    C#中foreach語句使用break暫停遍歷的方法

    這篇文章主要介紹了C#中foreach語句使用break暫停遍歷的方法,涉及C#中break語句跳出foreach循環(huán)的使用技巧,非常具有實用價值,是C#初學(xué)者必須掌握的重要技巧,需要的朋友可以參考下
    2015-04-04
  • Unity實現(xiàn)主角移動與攝像機跟隨

    Unity實現(xiàn)主角移動與攝像機跟隨

    這篇文章主要為大家詳細介紹了Unity實現(xiàn)主角移動與攝像機跟隨,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • c# 如何實現(xiàn)一個簡單的json解析器

    c# 如何實現(xiàn)一個簡單的json解析器

    這篇文章主要介紹了c# 如何實現(xiàn)一個簡單的json解析器,文中講解非常細致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07

最新評論

西峡县| 岑溪市| 汕尾市| 手游| 垦利县| 晋城| 滁州市| 桃源县| 宁乡县| 延吉市| 安吉县| 厦门市| 介休市| 尼木县| 叙永县| 罗甸县| 开远市| 铁力市| 贵州省| 嘉定区| 册亨县| 辽宁省| 铜陵市| 垫江县| 巴彦淖尔市| 晋江市| 西充县| 正定县| 紫金县| 临邑县| 吉林省| 左云县| 通渭县| 长宁县| 中方县| 凤台县| 西丰县| 博客| 土默特右旗| 澄城县| 鞍山市|