ExceptionAggregator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Linq / Parallel / Utils / ExceptionAggregator.cs / 1305376 / ExceptionAggregator.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// 
// ExceptionAggregator.cs 
//
// [....] 
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

 
using System;
using System.Collections.Generic; 
using System.Threading; 

namespace System.Linq.Parallel 
{
    internal static class ExceptionAggregator
    {
        ///  
        /// WrapEnumerable.ExceptionAggregator wraps the enumerable with another enumerator that will
        /// catch exceptions, and wrap each with an AggregateException. 
        /// 
        /// If PLINQ decides to execute a query sequentially, we will reuse LINQ-to-objects
        /// implementations for the different operators. However, we still need to throw 
        /// AggregateException in the cases when parallel execution would have thrown an
        /// AggregateException. Thus, we introduce a wrapper enumerator that catches exceptions
        /// and wraps them with an AggregateException.
        ///  
        internal static IEnumerable WrapEnumerable(IEnumerable source, CancellationState cancellationState)
        { 
            using (IEnumerator enumerator = source.GetEnumerator()) 
            {
                while (true) 
                {
                    TElement elem = default(TElement);
                    try
                    { 
                        if (!enumerator.MoveNext())
                        { 
                            yield break; 
                        }
                        elem = enumerator.Current; 
                    }
                    catch (ThreadAbortException)
                    {
                        // Do not wrap ThreadAbortExceptions 
                        throw;
                    } 
                    catch (Exception ex) 
                    {
                        ThrowOCEorAggregateException(ex, cancellationState); 
                    }
                    yield return elem;
                }
            } 

        } 
 

        ///  
        /// A variant of WrapEnumerable that accepts a QueryOperatorEnumerator{,} instead of an IEnumerable{}.
        /// The code duplication is necessary to avoid extra virtual method calls that would otherwise be needed to
        /// convert the QueryOperatorEnumerator{,} to an IEnumerator{}.
        ///  
        internal static IEnumerable WrapQueryEnumerator(QueryOperatorEnumerator source,
            CancellationState cancellationState) 
        { 
            TElement elem = default(TElement);
            TIgnoreKey ignoreKey = default(TIgnoreKey); 

            try
            {
                while (true) 
                {
                    try 
                    { 
                        if (!source.MoveNext(ref elem, ref ignoreKey))
                        { 
                            yield break;
                        }
                    }
                    catch (ThreadAbortException) 
                    {
                        // Do not wrap ThreadAbortExceptions 
                        throw; 
                    }
                    catch (Exception ex) 
                    {
                        ThrowOCEorAggregateException(ex, cancellationState);
                    }
 
                    yield return elem;
                } 
            } 
            finally
            { 
                source.Dispose();
            }
        }
 
        /// 
        /// Accepts an exception, wraps it as if it was crossing the parallel->sequential boundary, and throws the 
        /// wrapped exception. In sequential fallback cases, we use this method to throw exceptions that are consistent 
        /// with exceptions thrown by PLINQ when the query is executed by worker tasks.
        /// 
        /// The exception will be wrapped into an AggregateException, except for the case when the query is being
        /// legitimately cancelled, in which case we will propagate the CancellationException with the appropriate
        /// token.
        ///  
        internal static void ThrowOCEorAggregateException(Exception ex, CancellationState cancellationState)
        { 
            if (ThrowAnOCE(ex, cancellationState)) 
            {
                CancellationState.ThrowWithStandardMessageIfCanceled( 
                    cancellationState.ExternalCancellationToken);
            }
            else
            { 
                throw new AggregateException(ex);
            } 
        } 

 
        /// 
        /// Wraps a function with a try/catch that morphs all exceptions into AggregateException.
        /// 
        /// The input argument type. 
        /// The return value type.
        /// A function to use internally. 
        /// The cancellation state to use. 
        /// A new function containing exception wrapping logic.
        internal static Func WrapFunc(Func f, CancellationState cancellationState) 
        {
            return t =>
                {
                    U retval = default(U); 
                    try
                    { 
                         retval = f(t); 
                    }
                    catch (ThreadAbortException) 
                    {
                        // Do not wrap ThreadAbortExceptions
                        throw;
                    } 
                    catch (Exception ex)
                    { 
                        ThrowOCEorAggregateException(ex, cancellationState); 
                    }
                    return retval; 
                };
        }

        // return: true ==> throw an OCE(externalCT) 
        //         false ==> thrown an AggregateException(ex).
        private static bool ThrowAnOCE(Exception ex, CancellationState cancellationState) 
        { 
            // if the query has been canceled and the exception represents this, we want to throw OCE
            // but otherwise we want to throw an AggregateException to mimic normal Plinq operation 
            // See QueryTaskGroupState.WaitAll for the main plinq exception handling logic.

            // check for co-operative cancellation.
            OperationCanceledException cancelEx = ex as OperationCanceledException; 
            if (cancelEx != null &&
                cancelEx.CancellationToken == cancellationState.ExternalCancellationToken 
                && cancellationState.ExternalCancellationToken.IsCancellationRequested) 
            {
                return true;  // let the OCE(extCT) be rethrown. 
            }

            // check for external cancellation which triggered the mergedToken.
            if (cancelEx != null && 
                cancelEx.CancellationToken == cancellationState.MergedCancellationToken
                && cancellationState.MergedCancellationToken.IsCancellationRequested 
                && cancellationState.ExternalCancellationToken.IsCancellationRequested) 
            {
                return true;  // convert internal cancellation back to OCE(extCT). 
            }

            return false;
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK