private static AppDomainDelegate BuildAppDomainDelegate(
            this DisposableAppDomain disposableAppDomain)
        {
            // ReSharper disable once AssignNullToNotNullAttribute
            var result = (AppDomainDelegate)disposableAppDomain.AppDomain.CreateInstanceAndUnwrap(
                typeof(AppDomainDelegate).Assembly.FullName,
                typeof(AppDomainDelegate).FullName);

            return(result);
        }
        /// <summary>
        /// Executes the specified <see cref="Action"/> in the specified Domain.
        /// </summary>
        /// <param name="action">The action to execute.</param>
        /// <param name="disposableAppDomain">The Domain within which to execute the specified action.</param>
        public static void ExecuteInAppDomain(
            this Action action,
            DisposableAppDomain disposableAppDomain)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            if (disposableAppDomain == null)
            {
                throw new ArgumentNullException(nameof(disposableAppDomain));
            }

            disposableAppDomain.Execute(action);
        }
        /// <summary>
        /// Executes the specified <see cref="Func{TResult}"/> in the specified Domain.
        /// </summary>
        /// <typeparam name="TResult">The type of the return value of the method that <paramref name="func"/> encapsulates.</typeparam>
        /// <param name="func">The func to execute.</param>
        /// <param name="disposableAppDomain">The Domain within which to execute the specified func.</param>
        /// <returns>
        /// The return value from executing the specified <see cref="Func{TResult}"/> in the specified Domain.
        /// </returns>
        public static TResult ExecuteInAppDomain <TResult>(
            this Func <TResult> func,
            DisposableAppDomain disposableAppDomain)
        {
            if (func == null)
            {
                throw new ArgumentNullException(nameof(func));
            }

            if (disposableAppDomain == null)
            {
                throw new ArgumentNullException(nameof(disposableAppDomain));
            }

            var result = disposableAppDomain.Execute(func);

            return(result);
        }
        /// <summary>
        /// Executes the specified <see cref="Action"/> in the specified Domain.
        /// </summary>
        /// <param name="disposableAppDomain">The Domain within which to execute the specified action.</param>
        /// <param name="action">The action to execute.</param>
        public static void Execute(
            this DisposableAppDomain disposableAppDomain,
            Action action)
        {
            if (disposableAppDomain == null)
            {
                throw new ArgumentNullException(nameof(disposableAppDomain));
            }

            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            var domainDelegate = disposableAppDomain.BuildAppDomainDelegate();

            domainDelegate.Execute(action);
        }
        /// <summary>
        /// Creates a disposable <see cref="AppDomain"/>.
        /// </summary>
        /// <param name="name">OPTIONAL friendly name of the domain.  DEFAULT uses <see cref="Guid.NewGuid"/>.</param>
        /// <param name="securityInfo">OPTIONAL object that contains evidence mapped through the security policy to establish a top-of-stack permission set.  DEFAULT to create a new <see cref="Evidence"/> using the <see cref="AppDomain.Evidence"/> of the <see cref="AppDomain.CurrentDomain"/>.</param>
        /// <param name="appDomainInfo">OPTIONAL object that contains application domain initialization information.  DEFAULT is to use a new <see cref="AppDomainSetup"/>, setting <see cref="AppDomainSetup.ApplicationBase"/> using <see cref="AppDomainSetup.ApplicationBase"/> of the <see cref="AppDomain.CurrentDomain"/>.</param>
        /// <returns>
        /// A disposable <see cref="AppDomain"/>.
        /// </returns>
        public static DisposableAppDomain CreateDisposableAppDomain(
            string name                  = null,
            Evidence securityInfo        = null,
            AppDomainSetup appDomainInfo = null)
        {
            name = name ?? Guid.NewGuid().ToString();

            securityInfo = securityInfo ?? new Evidence(AppDomain.CurrentDomain.Evidence);

            appDomainInfo = appDomainInfo ?? new AppDomainSetup
            {
                ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
            };

            var appDomain = AppDomain.CreateDomain(name, securityInfo, appDomainInfo);

            var result = new DisposableAppDomain(appDomain);

            return(result);
        }
        /// <summary>
        /// Executes the specified <see cref="Func{TResult}"/> in the specified Domain.
        /// </summary>
        /// <typeparam name="TResult">The type of the return value of the method that <paramref name="func"/> encapsulates.</typeparam>
        /// <param name="disposableAppDomain">The Domain within which to execute the specified func.</param>
        /// <param name="func">The func to execute.</param>
        /// <returns>
        /// The return value from executing the specified <see cref="Func{TResult}"/> in the specified Domain.
        /// </returns>
        public static TResult Execute <TResult>(
            this DisposableAppDomain disposableAppDomain,
            Func <TResult> func)
        {
            if (disposableAppDomain == null)
            {
                throw new ArgumentNullException(nameof(disposableAppDomain));
            }

            if (func == null)
            {
                throw new ArgumentNullException(nameof(func));
            }

            var domainDelegate = disposableAppDomain.BuildAppDomainDelegate();

            var result = domainDelegate.Execute(func);

            return(result);
        }
        /// <summary>
        /// Executes the specified <see cref="Func{T1, T2, T3, TResult}"/> in the specified Domain.
        /// </summary>
        /// <typeparam name="T1">The type of the first parameter of the method that <paramref name="func"/> encapsulates.</typeparam>
        /// <typeparam name="T2">The type of the second parameter of the method that <paramref name="func"/> encapsulates.</typeparam>
        /// <typeparam name="T3">The type of the third parameter of the method that <paramref name="func"/> encapsulates.</typeparam>
        /// <typeparam name="TResult">The type of the return value of the method that <paramref name="func"/> encapsulates.</typeparam>
        /// <param name="func">The func to execute.</param>
        /// <param name="parameter1">The first parameter to pass to the method that <paramref name="func"/> encapsulates.</param>
        /// <param name="parameter2">The second parameter to pass to the method that <paramref name="func"/> encapsulates.</param>
        /// <param name="parameter3">The third parameter to pass to the method that <paramref name="func"/> encapsulates.</param>
        /// <param name="disposableAppDomain">The Domain within which to execute the specified func.</param>
        /// <returns>
        /// The return value from executing the specified <see cref="Func{T1, T2, T3, TResult}"/> in the specified Domain.
        /// </returns>
        public static TResult ExecuteInAppDomain <T1, T2, T3, TResult>(
            this Func <T1, T2, T3, TResult> func,
            T1 parameter1,
            T2 parameter2,
            T3 parameter3,
            DisposableAppDomain disposableAppDomain)
        {
            if (func == null)
            {
                throw new ArgumentNullException(nameof(func));
            }

            if (disposableAppDomain == null)
            {
                throw new ArgumentNullException(nameof(disposableAppDomain));
            }

            var result = disposableAppDomain.Execute(func, parameter1, parameter2, parameter3);

            return(result);
        }