溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

c# 基于任務(wù)的異步編程模式實現(xiàn)異常處理

發(fā)布時間:2020-11-03 15:47:37 來源:億速云 閱讀:227 作者:Leah 欄目:開發(fā)技術(shù)

本篇文章為大家展示了c# 基于任務(wù)的異步編程模式實現(xiàn)異常處理,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

1、沒有等待的調(diào)用異步方法

ThrowAfter方法是在一定延遲后拋出一個異常:

private async Task ThrowAfter(int ms,string message)
{
  await Task.Delay(ms);
  Console.WriteLine("異步任務(wù)隨后將拋出異常。");
  throw new Exception(message);
}

DontHandle方法在調(diào)用異步方法時,由于有滯后性,所以使用try...catch...不能捕獲到異步方法中的異常。

public void DontHandle()
{
  try
  {
    ThrowAfter(200, "異步方法拋出的異常");
  }
  catch(Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  Console.WriteLine("完成方法:DontHandle");
}

注意:返回void的異步方法不會等待。因為從async void方法拋出的異常無法捕獲。因此,異步方法最好返回一個Task類型。

2、異步方法的異常處理

異步方法異常的比較好的處理方式使使用await關(guān)鍵字,將其放在try/catch語句中。

public async void HandleOneError()
{
  Console.WriteLine("HandleOneError方法開始執(zhí)行。。。");
  try
  {
    await ThrowAfter(2000, "異步方法拋出的異常");
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  Console.WriteLine("完成方法:HandleOneError");
}

調(diào)用ThrowAfter方法后,HandleOneError會釋放線程,但它會在任務(wù)完成時保持對任務(wù)的引用。當(dāng)異步方法拋出異常,會調(diào)用匹配的catch塊內(nèi)的代碼。

3、多個異步方法的異常處理

如果調(diào)用多個異步方法,會有多個拋出異常,在捕獲異常時就會有問題。

public async void StartTwoTasks()
{
  Console.WriteLine("StartTwoTasks方法開始執(zhí)行。。。");
  try
  {
    await ThrowAfter(2000, "first");//先執(zhí)行該方法
    await ThrowAfter(1000, "Second");//第一個異步方法正常執(zhí)行完后才會執(zhí)行該方法
  }
  catch(Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  Console.WriteLine("完成方法:StartTwoTasks");
}

StartTwoTasks方法中,調(diào)用了兩個異步方法。理論上認(rèn)為,當(dāng)?shù)谝粋€異步方法執(zhí)行完,拋出異常后,緊接著就會調(diào)用第二個異步方法,并拋出異常。但實際上是第一個異步方法拋出異常之后,就會被catch捕獲,并不會執(zhí)行第二個異步方法。因為這種類型中,在“基于任務(wù)的異步編程模式(TAP)”一文中解釋過,這種調(diào)用方法是等待第一個異步方法執(zhí)行結(jié)束后,調(diào)用函數(shù)的線程控制權(quán)才會調(diào)用第二個異步方法,多個異步方法以此類推。但是當(dāng)時我們使用了Task類中的WhenAll方法同時等待多個任務(wù)全部執(zhí)行完,才執(zhí)行后面的代碼。

public async void StartTwoTasksParallel()
{
  Console.WriteLine("StartTwoTasksParallel方法開始執(zhí)行。。。");
  try
  {
    Task t1 = ThrowAfter(2000, "first");//先執(zhí)行該方法
    Task t2 = ThrowAfter(1000, "Second");//第一個異步方法執(zhí)行完后才會執(zhí)行該方法
    await Task.WhenAll(t1, t2);
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  Console.WriteLine("完成方法:StartTwoTasksParallel");
}

StartTwoTasksParallel方法使用Task類的WhenAll方法,并行調(diào)用兩個不關(guān)聯(lián)的異步方法。該方法將等待所有任務(wù)結(jié)束后才結(jié)束調(diào)用,不論任何一個拋出異常都不會影響其他任務(wù)。但是,該方法只會捕獲第一個異常(先拋出異常的任務(wù)),其他異常將不會被顯示。

有一種方法可以獲取所有任務(wù)的異常信息,就是在try塊外聲明任務(wù)變量t1和t2,讓這兩個變量在catch塊內(nèi)訪問。在catch塊中檢測任務(wù)的IsFaulted屬性確認(rèn)任務(wù)的狀態(tài),以判定是否出現(xiàn)異常,然后通過Task類的Exception.InnerException訪問異常信息本身。

4、使用AggregateException信息

Task.WhenAll方法返回一個Task的結(jié)果變量。catch語句只會捕捉到所有異步任務(wù)中的第一個異常,但是Task.WhenAll方法返回的Task類型結(jié)果變量中會包含所有任務(wù)都出現(xiàn)的異常。外部結(jié)果任務(wù)的Exception屬性是一個AggregateException類型,顯示所有異常只需要遍歷結(jié)果任務(wù)中的Exception的InnerExceptions屬性即可。

public async void ShowAggregatedException()
{
  Console.WriteLine("ShowAggregatedException方法開始執(zhí)行。。。");
  Task taskResult = null;
  try
  {
    Task t1 = ThrowAfter(2000, "first");//先執(zhí)行該方法
    Task t2 = ThrowAfter(1000, "second");//第一個異步方法執(zhí)行完后才會執(zhí)行該方法
    Task t3 = ThrowAfter(1500, "third");//第一個異步方法執(zhí)行完后才會執(zhí)行該方法
    await (taskResult = Task.WhenAll(t1, t2, t3));
  }
  catch (Exception ex)
  {
    Console.WriteLine("handle {0}",ex.Message);
    foreach (Exception ex1 in taskResult.Exception.InnerExceptions)
    {
      Console.WriteLine("Inner exception {0}", ex1.Message);
    }
  }
  Console.WriteLine("完成方法:ShowAggregatedException");
}

上述內(nèi)容就是c# 基于任務(wù)的異步編程模式實現(xiàn)異常處理,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI