All files
[pithos-ms-client] / trunk / Libraries / ParallelExtensionsExtras / Extensions / AggregateExceptionExtensions.cs
1 //--------------------------------------------------------------------------
2 // 
3 //  Copyright (c) Microsoft Corporation.  All rights reserved. 
4 // 
5 //  File: AggregateExceptionExtensions.cs
6 //
7 //--------------------------------------------------------------------------
8
9 using System.Collections.Generic;
10
11 namespace System
12 {
13     /// <summary>Extension methods for AggregateException.</summary>
14     public static class AggregateExceptionExtensions
15     {
16         /// <summary>Invokes a handler on each Exception contained by this AggregateException.</summary>
17         /// <param name="aggregateException">The AggregateException.</param>
18         /// <param name="predicate">
19         /// The predicate to execute for each exception. The predicate accepts as an argument the Exception
20         /// to be processed and returns a Boolean to indicate whether the exception was handled.
21         /// </param>
22         /// <param name="leaveStructureIntact">
23         /// Whether the rethrown AggregateException should maintain the same hierarchy as the original.
24         /// </param>
25         public static void Handle(
26             this AggregateException aggregateException,
27             Func<Exception, bool> predicate, bool leaveStructureIntact)
28         {
29             if (aggregateException == null) throw new ArgumentNullException("aggregateException");
30             if (predicate == null) throw new ArgumentNullException("predicate");
31
32             // If leaveStructureIntact, use this implementation
33             if (leaveStructureIntact)
34             {
35                 var result = HandleRecursively(aggregateException, predicate);
36                 if (result != null) throw result;
37             }
38                 // Otherwise, default back to the implementation on AggregateException
39             else aggregateException.Handle(predicate);
40         }
41
42         private static AggregateException HandleRecursively(
43             AggregateException aggregateException, Func<Exception, bool> predicate)
44         {   
45             // Maintain a list of exceptions to be rethrown
46             List<Exception> innerExceptions = null;
47
48             // Loop over all of the inner exceptions
49             foreach(var inner in aggregateException.InnerExceptions)
50             {
51                 // If the inner exception is itself an aggregate, process recursively
52                 AggregateException innerAsAggregate = inner as AggregateException;
53                 if (innerAsAggregate != null)
54                 {
55                     // Process recursively, and if we get back a new aggregate, store it
56                     AggregateException newChildAggregate = HandleRecursively(innerAsAggregate, predicate);
57                     if (newChildAggregate != null)
58                     {
59                         if (innerExceptions != null) innerExceptions = new List<Exception>();
60                         innerExceptions.Add(newChildAggregate);
61                     }
62                 }
63                     // Otherwise, if the exception does not match the filter, store it
64                 else if (!predicate(inner))
65                 {
66                     if (innerExceptions != null) innerExceptions = new List<Exception>();
67                     innerExceptions.Add(inner);
68                 }
69             }
70             
71             // If there are any remaining exceptions, return them in a new aggregate.
72             return innerExceptions.Count > 0 ?
73                 new AggregateException(aggregateException.Message, innerExceptions) :
74                 null;
75         }
76     }
77 }