/// <summary>
        /// Tries to call an instance method with the specified name, a single parameter, and a return value.
        /// </summary>
        /// <typeparam name="TArg1">The type of the method's single parameter.</typeparam>
        /// <typeparam name="TResult">The type of the method's result value.</typeparam>
        /// <param name="source">The object to call the method on.</param>
        /// <param name="methodName">The name of the method to call.</param>
        /// <param name="arg1">The value to pass as the method's single argument.</param>
        /// <param name="value">The value returned by the method.</param>
        /// <returns><c>true</c> if the method was found, <c>false</c> otherwise.</returns>
        public static bool TryCallMethod <TArg1, TResult>(this object source, string methodName, TArg1 arg1, out TResult value)
        {
            var type       = source.GetType();
            var paramType1 = typeof(TArg1);
            var returnType = typeof(TResult);

            var cachedItem = Cache.GetOrAdd(
                new PropertyFetcherCacheKey(type, paramType1, returnType, methodName),
                key =>
                DynamicMethodBuilder <Func <object, TArg1, TResult> >
                .CreateMethodCallDelegate(
                    key.Type1,
                    key.Name,
                    OpCodeValue.Callvirt,
                    methodParameterTypes: new[] { key.Type2 }));

            if (cachedItem is Func <object, TArg1, TResult> func)
            {
                value = func(source, arg1);
                return(true);
            }

            value = default;
            return(false);
        }
        /// <summary>
        /// Tries to call an instance method with the specified name, two parameters, and no return value.
        /// </summary>
        /// <typeparam name="TArg1">The type of the method's first parameter.</typeparam>
        /// <typeparam name="TArg2">The type of the method's second parameter.</typeparam>
        /// <param name="source">The object to call the method on.</param>
        /// <param name="methodName">The name of the method to call.</param>
        /// <param name="arg1">The value to pass as the method's first argument.</param>
        /// <param name="arg2">The value to pass as the method's second argument.</param>
        /// <returns><c>true</c> if the method was found, <c>false</c> otherwise.</returns>
        public static bool TryCallVoidMethod <TArg1, TArg2>(this object source, string methodName, TArg1 arg1, TArg2 arg2)
        {
            var type       = source.GetType();
            var paramType1 = typeof(TArg1);
            var paramType2 = typeof(TArg2);

            var cachedItem = Cache.GetOrAdd(
                new PropertyFetcherCacheKey(type, paramType1, paramType2, methodName),
                key =>
                DynamicMethodBuilder <Action <object, TArg1, TArg2> >
                .CreateMethodCallDelegate(
                    key.Type1,
                    key.Name,
                    OpCodeValue.Callvirt,
                    methodParameterTypes: new[] { key.Type2, key.Type3 }));

            if (cachedItem is Action <object, TArg1, TArg2> func)
            {
                func(source, arg1, arg2);
                return(true);
            }

            return(false);
        }