protected virtual Delegate GetMethodDelegateInternal(Type delegateType, MethodInfo method)
        {
            lock (InvokeMethodCacheDelegate)
            {
                var      cacheKey = new MethodDelegateCacheKey(method, delegateType);
                Delegate value;
                if (!InvokeMethodCacheDelegate.TryGetValue(cacheKey, out value))
                {
                    GenerateInvokeMethodCode(method, delegateType);
                    MethodInfo delegateMethod = delegateType.GetMethodEx(nameof(Action.Invoke));
                    if (delegateMethod == null)
                    {
                        throw new ArgumentException(string.Empty, nameof(delegateType));
                    }

                    var             delegateParams = delegateMethod.GetParameters().ToList();
                    ParameterInfo[] methodParams   = method.GetParameters();
                    var             expressions    = new List <Expression>();
                    var             parameters     = new List <ParameterExpression>();
                    if (!method.IsStatic)
                    {
                        var thisParam = Expression.Parameter(delegateParams[0].ParameterType, "@this");
                        parameters.Add(thisParam);
                        expressions.Add(ConvertIfNeed(thisParam, method.DeclaringType, false));
                        delegateParams.RemoveAt(0);
                    }
                    Should.BeValid("delegateType", delegateParams.Count == methodParams.Length);
                    for (int i = 0; i < methodParams.Length; i++)
                    {
                        ParameterExpression parameter = Expression.Parameter(delegateParams[i].ParameterType, i.ToString());
                        parameters.Add(parameter);
                        expressions.Add(ConvertIfNeed(parameter, methodParams[i].ParameterType, false));
                    }

                    Expression callExpression;
                    if (method.IsStatic)
                    {
                        callExpression = Expression.Call(null, method, expressions.ToArrayEx());
                    }
                    else
                    {
                        Expression @this = expressions[0];
                        expressions.RemoveAt(0);
                        callExpression = Expression.Call(@this, method, expressions.ToArrayEx());
                    }

                    if (delegateMethod.ReturnType != typeof(void))
                    {
                        callExpression = ConvertIfNeed(callExpression, delegateMethod.ReturnType, false);
                    }
                    var lambdaExpression = Expression.Lambda(delegateType, callExpression, parameters);
                    value = lambdaExpression.Compile();
                    InvokeMethodCacheDelegate[cacheKey] = value;
                }
                return(value);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        ///     Gets a delegate to call the specified <see cref="MethodInfo" />.
        /// </summary>
        /// <param name="delegateType">The type of delegate.</param>
        /// <param name="method">
        ///     The specified <see cref="MethodInfo" />
        /// </param>
        /// <returns>
        ///     An instance of delegate.
        /// </returns>
        public virtual Delegate GetMethodDelegate(Type delegateType, MethodInfo method)
        {
            Should.NotBeNull(delegateType, "delegateType");
            Should.BeOfType <Delegate>(delegateType, "delegateType");
            Should.NotBeNull(method, "method");
            lock (InvokeMethodCacheDelegate)
            {
                var      cacheKey = new MethodDelegateCacheKey(method, delegateType);
                Delegate value;
                if (!InvokeMethodCacheDelegate.TryGetValue(cacheKey, out value))
                {
                    MethodInfo      delegateMethod = delegateType.GetMethodEx("Invoke");
                    var             delegateParams = delegateMethod.GetParameters().ToList();
                    ParameterInfo[] methodParams   = method.GetParameters();
                    var             expressions    = new List <Expression>();
                    var             parameters     = new List <ParameterExpression>();
                    if (!method.IsStatic)
                    {
                        var thisParam = Expression.Parameter(delegateParams[0].ParameterType, "@this");
                        parameters.Add(thisParam);
                        expressions.Add(ConvertIfNeed(thisParam, GetDeclaringType(method), false));
                        delegateParams.RemoveAt(0);
                    }
                    Should.BeValid("delegateType", delegateParams.Count == methodParams.Length);
                    for (int i = 0; i < methodParams.Length; i++)
                    {
                        ParameterExpression parameter = Expression.Parameter(delegateParams[i].ParameterType, i.ToString());
                        parameters.Add(parameter);
                        expressions.Add(ConvertIfNeed(parameter, methodParams[i].ParameterType, false));
                    }

                    Expression callExpression;
                    if (method.IsStatic)
                    {
                        callExpression = Expression.Call(null, method, expressions.ToArrayEx());
                    }
                    else
                    {
                        Expression @this = expressions[0];
                        expressions.RemoveAt(0);
                        callExpression = Expression.Call(@this, method, expressions.ToArrayEx());
                    }

                    if (delegateMethod.ReturnType != typeof(void))
                    {
                        callExpression = ConvertIfNeed(callExpression, delegateMethod.ReturnType, false);
                    }
                    var lambdaExpression = CreateLambdaExpressionByType(delegateType, callExpression, parameters);
                    value = lambdaExpression.Compile();
                    InvokeMethodCacheDelegate[cacheKey] = value;
                }
                return(value);
            }
        }