public void ChainFallbacksTest()
        {
            int callsToFirst = 0, callsToSecond = 0;
            VariadicArrayParametersDelegate
                first = args => { throw new Exception($"{++callsToFirst}"); },
            second    = args => { callsToSecond++; return(4); };

            Assert.AreEqual(expected: 0, actual: callsToFirst);
            Assert.AreEqual(expected: 0, actual: callsToSecond);

            var result = new[] { first, second }.ChainFallbacks();

            Assert.AreEqual(expected: 0, actual: callsToFirst);
            Assert.AreEqual(expected: 0, actual: callsToSecond);

            Assert.Throws <Exception>(() => first());
            Assert.AreEqual(expected: 1, actual: callsToFirst);
            Assert.AreEqual(expected: 0, actual: callsToSecond);

            Assert.AreEqual(expected: 4, actual: second());
            Assert.AreEqual(expected: 1, actual: callsToFirst);
            Assert.AreEqual(expected: 1, actual: callsToSecond);

            Assert.AreEqual(expected: 4, actual: result());
            Assert.AreEqual(expected: 2, actual: callsToFirst);
            Assert.AreEqual(expected: 2, actual: callsToSecond);

            Assert.AreEqual(expected: 4, actual: result());
            Assert.AreEqual(expected: 2, actual: callsToFirst);
            Assert.AreEqual(expected: 3, actual: callsToSecond);
        }
        public void DelegateWrappingTest()
        {
            VariadicArrayParametersDelegate del = args => (int)args[0] + (int)args[1];

            Func <int, int, int> wrapped = del.WrapDelegate <Func <int, int, int> >();

            int result = wrapped(30, 12);

            Assert.AreEqual(expected: 42, actual: result);
        }
        internal static VariadicArrayParametersDelegate CreateLazy(this Func <VariadicArrayParametersDelegate> creator)
        {
            VariadicArrayParametersDelegate delegat = null;

            return(args => {
                if (delegat == null)
                {
                    delegat = creator();
                }

                return delegat.Invoke(args);
            });
        }
        public void CreateLazyIsLazyTest()
        {
            int creationCount = 0;
            Func <VariadicArrayParametersDelegate> creator = () => {
                creationCount++;
                return(args => "success!");
            };

            Assert.AreEqual(expected: 0, actual: creationCount);

            VariadicArrayParametersDelegate delegat = creator.CreateLazy();

            Assert.AreEqual(expected: 0, actual: creationCount);

            Assert.AreEqual(expected: "success!", actual: delegat.Invoke());
            Assert.AreEqual(expected: 1, actual: creationCount);

            Assert.AreEqual(expected: "success!", actual: delegat.Invoke());
            Assert.AreEqual(expected: 1, actual: creationCount);
        }
        /// <summary>
        /// Constructs a delegate of type <typeparamref name="D"/> that calls the given <see cref="VariadicArrayParametersDelegate"/>.
        /// </summary>
        /// <remarks>
        /// Uses <see cref="Expression{TDelegate}.Compile"/> internally, but only once for each type <typeparamref name="D"/>
        /// provided.
        /// </remarks>
        public static D WrapDelegate <D>(this VariadicArrayParametersDelegate delegat) where D : class
        {
            var builder = builders.GetOrAdd(typeof(D), (Type t) => getBuilderExpression <D>().Compile());

            return((D)builder(delegat));
        }