C# parallel extensions for the Delegate class.

//--------------------------------------------------------------------------
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
//  File: DelegateExtensions.cs
//
//--------------------------------------------------------------------------

using System.Diagnostics;
using System.Linq;

namespace System
{
    /// <summary>Parallel extensions for the Delegate class.</summary>
    public static class DelegateExtensions
    {
        /// <summary>Dynamically invokes (late-bound) in parallel the methods
        /// represented by the delegate.</summary>
        /// <param name="multicastDelegate">The delegate to be invoked.</param>
        /// <param name="args">An array of objects that are the arguments to pass to the delegates.</param>
        /// <returns>The return value of one of the delegate invocations.</returns>
        public static object ParallelDynamicInvoke(this Delegate multicastDelegate, params object[] args)
        {
            if (multicastDelegate == null) throw new ArgumentNullException(nameof(multicastDelegate));
            if (args == null) throw new ArgumentNullException(nameof(args));

            return multicastDelegate.GetInvocationList()
                .AsParallel().AsOrdered()
                .Select(d => d.DynamicInvoke(args))
                .Last();
        }

        /// <summary>
        /// Provides a delegate that runs the specified action and fails fast
        /// if the action throws an exception.
        /// </summary>
        /// <param name="action">The action to invoke.</param>
        /// <returns>The wrapper delegate.</returns>
        public static Action WithFailFast(this Action action)
        {
            return () =>
            {
                try
                {
                    action();
                }
                catch (Exception exc)
                {
                    if (Debugger.IsAttached)
                    {
                        Debugger.Break();
                    }
                    else
                    {
                        Environment.FailFast("An unhandled exception occurred.", exc);
                    }
                }
            };
        }

        /// <summary>
        /// Provides a delegate that runs the specified function and fails fast
        /// if the function throws an exception.
        /// </summary>
        /// <param name="function">The function to invoke.</param>
        /// <returns>The wrapper delegate.</returns>
        public static Func<T> WithFailFast<T>(this Func<T> function)
        {
            return () =>
            {
                try
                {
                    return function();
                }
                catch (Exception exc)
                {
                    if (Debugger.IsAttached)
                    {
                        Debugger.Break();
                    }
                    else
                    {
                        Environment.FailFast("An unhandled exception occurred.", exc);
                    }
                }

                throw new Exception("Will never get here");
            };
        }
    }
}