2011-07-19 65 views
15

我看到在網絡上AggregateException的一個例子,我想弄清楚它是如何工作的,所以我寫了簡單的例子,但我出於某種原因碼不起作用AggregateException C#示例

有人能解釋我有什麼問題

public static void Main() 
    { 
     try 
     { 
      Parallel.For(0, 500000, i => 
      { 
       if (i == 10523) 
        throw new TimeoutException("i = 10523"); 

       Console.WriteLine(i + "\n"); 
      }); 
     } 
     catch (AggregateException exception) 
     { 
      foreach (Exception ex in exception.InnerExceptions) 
      { 
       Console.WriteLine(ex.ToString()); 
      } 
     } 
    } 
+0

什麼是不工作?你期望發生什麼? – Klinger

+0

超時異常未由用戶代碼處理 – Dan

+0

您所說的是,您期待的是由catch塊處理的異常,但您會得到「超時異常不由用戶代碼處理」,對嗎?如果是這樣的話,Yahia的回答和評論可能就是你要找的。 – Klinger

回答

7

當使用並行時,「作業」(這裏從0到500000計數)被分割到多個工作線程。 這些都可能會引發異常。在示例中,異常編碼在10523線程中發生。 在現實世界的場景中,可能會發生多個異常(在不同的線程中) - AggregateException僅僅是一個「容器」,用於在Parallel運行時發生的所有異常以便您不會丟失任何異常...

+1

是的,這很好,但我不明白的是爲什麼我得到一個「錯誤」,說超時異常不是由用戶代碼處理。不應該聚合異常捕獲這個異常並打印一次平行的控制檯完成其工作? – Dan

+2

你是對的,但我認爲你所描述的行爲只是在VS上運行時進行調試。 – Yahia

+0

@Dan:通過在VS之外運行示例並且沒有捕獲塊獲得異常是AggregateException:發生了一個或多個錯誤。 – Klinger

3

AggregateException通常用於捕獲異常,這可能會在等待Task完成時發生。因爲Task一般可以由多個其他人組成,所以我們不知道是否會拋出一個或多個異常。

檢查下面的例子:

// set up your task 
Action<int> job = (int i) => 
{ 
    if (i % 100 == 0) 
     throw new TimeoutException("i = " + i); 
}; 

// we want many tasks to run in paralell 
var tasks = new Task[1000]; 
for (var i = 0; i < 1000; i++) 
{ 
    // assign to other variable, 
    // or it will use the same number for every task 
    var j = i; 
    // run your task 
    var task = Task.Run(() => job(j)); 
    // save it 
    tasks[i] = task; 
} 

try 
{ 
    // wait for all the tasks to finish in a blocking manner 
    Task.WaitAll(tasks); 

} 
catch (AggregateException e) 
{ 
    // catch whatever was thrown 
    foreach (Exception ex in e.InnerExceptions) 
     Console.WriteLine(ex.Message); 
} 
0

下面是實際使用AggregateException來得到一個異常對象內部異常,

private static Exception GetFirstRealException(Exception exception) 
    { 
     Exception realException = exception; 
     var aggregateException = realException as AggregateException; 

     if (aggregateException != null) 
     { 
      realException = aggregateException.Flatten().InnerException; // take first real exception 

      while (realException != null && realException.InnerException != null) 
      { 
       realException = realException.InnerException; 
      } 
     } 

     return realException ?? exception; 
    } 
5

五歲的時候,沒有人給出了正確的答案?您需要對內部異常調用「處理」。從MSDN關於「句柄」的文檔:

謂詞的每次調用返回true或false以指示是否處理了Exception。在所有調用之後,如果有任何異常未處理,則所有未處理的異常將被放入將拋出的新AggregateException中。否則,Handle方法會簡單地返回。如果謂詞的任何調用引發異常,它將停止處理任何更多的異常,並立即傳播拋出的異常。

示例代碼,也是從MSDN:

public static void Main() 
    { 
     var task1 = Task.Run(() => { throw new CustomException("This exception is expected!"); }); 

     try { 
      task1.Wait(); 
     } 
     catch (AggregateException ae) 
     { 
     // Call the Handle method to handle the custom exception, 
     // otherwise rethrow the exception. 
     ae.Handle(ex => { if (ex is CustomException) 
          Console.WriteLine(ex.Message); 
          return ex is CustomException; 
         }); 
     } 
    }