示例#1
0
        /// <summary>
        /// 创建指定的静态或实例方法的指定类型的开放方法委托。
        /// </summary>
        /// <param name="method">要调用的方法。</param>
        /// <param name="delegateType">要创建的委托的类型。</param>
        /// <returns><paramref name="delegateType"/> 类型的委托,表示静态或实例方法的委托。</returns>
        /// <remarks>如果是实例方法(非构造函数),需要将实例对象作为委托的第一个参数。
        /// 支持参数的强制类型转换,参数声明可以与实际类型不同。方法不能是包含泛型参数的非泛型定义。</remarks>
        /// <exception cref="MethodAccessException">调用方无权访问 <paramref name="method"/>。</exception>
        private static Delegate CreateOpenDelegate(MethodBase method, Type delegateType)
        {
            Contract.Requires(method != null && delegateType != null);
            // 判断是否需要作为实例的形参。
            int index = 0;

            if (!method.IsStatic && !(method is ConstructorInfo))
            {
                index++;
            }
            MethodInfo invoke = delegateType.GetInvokeMethod();

            Type[] paramTypes = invoke.GetParameterTypes();
            Type[] types      = paramTypes.Extend(method.GetParametersNoCopy().Length + index, typeof(Missing));
            Type   returnType = invoke.ReturnType;
            // 提取方法参数信息。
            MethodArgumentsInfo argumentsInfo = GetArgumentsInfo(ref method, types, returnType);

            if (argumentsInfo == null)
            {
                return(null);
            }
            // 构造动态委托。
            DynamicMethod dlgMethod = new DynamicMethod("MethodDelegate", returnType, paramTypes,
                                                        method.Module, true);
            ILGenerator il = dlgMethod.GetILGenerator();

            Contract.Assume(il != null);
            // 实例方法的第一个参数用作传递实例对象。
            if (argumentsInfo.InstanceType != null)
            {
                il.EmitLoadInstance(method, argumentsInfo.InstanceType, true);
            }
            // 加载方法参数。
            bool optimizeTailcall = il.EmitLoadParameters(method, argumentsInfo, index);

            // 调用方法。
            Type[] optionalArgumentTypes = null;
            if (argumentsInfo.OptionalArgumentTypes != null)
            {
                optionalArgumentTypes = argumentsInfo.OptionalArgumentTypes.ToArray();
            }
            if (!il.EmitInvokeMethod(method, optionalArgumentTypes, returnType, optimizeTailcall))
            {
                return(null);
            }
            return(dlgMethod.CreateDelegate(delegateType));
        }
示例#2
0
        /// <summary>
        /// 获取指定方法的参数信息。
        /// </summary>
        /// <param name="method">要获取参数信息的方法。</param>
        /// <param name="types">方法的实参类型列表。</param>
        /// <param name="returnType">方法的返回值类型。</param>
        /// <returns>方法的参数信息。</returns>
        private static MethodArgumentsInfo GetArgumentsInfo(ref MethodBase method, Type[] types, Type returnType)
        {
            MethodArgumentsOption options = MethodArgumentsOption.OptionalAndExplicit | MethodArgumentsOption.ConvertRefType;

            if (!method.IsStatic && !(method is ConstructorInfo))
            {
                options |= MethodArgumentsOption.ContainsInstance;
            }
            if (method.IsGenericMethodDefinition)
            {
                // 对泛型方法定义进行类型推断。
                MethodArgumentsInfo argumentsInfo = method.GenericArgumentsInferences(returnType, types, options);
                if (argumentsInfo == null)
                {
                    return(null);
                }
                method = ((MethodInfo)method).MakeGenericMethod(argumentsInfo.GenericArguments);
                argumentsInfo.UpdateParamArrayType(method);
                return(argumentsInfo);
            }
            // 调用时保证 !member.ContainsGenericParameters。
            return(MethodArgumentsInfo.GetInfo(method, types, options));
        }
示例#3
0
        /// <summary>
        /// 加载方法参数。
        /// </summary>
        /// <param name="il">IL 指令生成器。</param>
        /// <param name="method">要加载参数的方法。</param>
        /// <param name="argumentsInfo">方法实参信息。</param>
        /// <param name="firstArgument">第一个参数的值。</param>
        /// <returns>能否对方法进行 tailcall 优化,如果可以则返回 <c>true</c>;否则返回 <c>false</c>。</returns>
        private static bool EmitLoadParameters(this ILGenerator il, MethodBase method, MethodArgumentsInfo argumentsInfo,
                                               object firstArgument)
        {
            Contract.Requires(il != null && method != null && argumentsInfo != null);
            ParameterInfo[] parameters = method.GetParametersNoCopy();
            IList <Type>    args = argumentsInfo.FixedArguments;
            int             argCnt = args.Count, index = 0;
            bool            optimizeTailcall = true, firstArg = true;

            if (argCnt > 0)
            {
                firstArg = false;
                Type paramType = parameters[0].ParameterType;
                if (paramType.IsByRef)
                {
                    il.EmitConstant(Convert.ChangeType(firstArgument, paramType));
                    il.EmitGetAddress(paramType);
                    optimizeTailcall = false;
                }
                else
                {
                    il.EmitConstant(Convert.ChangeType(firstArgument, paramType));
                }
            }
            for (int i = 1; i < argCnt; i++, index++)
            {
                if (!il.EmitLoadParameter(parameters[i], index, args[i]))
                {
                    optimizeTailcall = false;
                }
            }
            if ((args = argumentsInfo.ParamArgumentTypes) != null)
            {
                // 加载 params 参数。
                argCnt = args.Count;
                Type elementType = argumentsInfo.ParamArrayType.GetElementType();
                Contract.Assume(elementType != null);
                il.EmitConstant(argCnt);
                il.Emit(OpCodes.Newarr, elementType);
                LocalBuilder local = il.GetLocal(argumentsInfo.ParamArrayType);
                il.Emit(OpCodes.Stloc, local);
                int i = 0;
                if (firstArg)
                {
                    i++;
                    il.EmitConstant(Convert.ChangeType(firstArgument, elementType));
                }
                for (; i < argCnt; i++, index++)
                {
                    il.Emit(OpCodes.Ldloc, local);
                    il.EmitConstant(i);
                    il.EmitLoadParameter(elementType, index, args[i]);
                    il.EmitStoreElement(elementType);
                }
                il.Emit(OpCodes.Ldloc, local);
                il.FreeLocal(local);
                optimizeTailcall = false;
            }
            else if ((args = argumentsInfo.OptionalArgumentTypes) != null)
            {
                // 加载可变参数。
                argCnt = args.Count;
                int i = 0;
                if (firstArg)
                {
                    i++;
                    il.EmitConstant(firstArgument);
                }
                for (; i < argCnt; i++, index++)
                {
                    il.EmitLoadParameter(args[i], index, args[i]);
                }
            }
            return(optimizeTailcall);
        }
示例#4
0
        /// <summary>
        /// 创建指定的静态或实例方法的指定类型的封闭方法委托。
        /// </summary>
        /// <param name="method">要调用的方法。</param>
        /// <param name="delegateType">要创建的委托的类型。</param>
        /// <param name="firstArgument">如果是实例方法(非构造函数),则作为委托要绑定到的对象;
        /// 否则将作为方法的第一个参数。</param>
        /// <param name="ensureClosed">如果确认方法一定是封闭委托,则为 <c>true</c>;若
        /// <paramref name="firstArgument"/> 为 <c>null</c> 时可能为开放委托,则为 <c>false</c>。</param>
        /// <returns><paramref name="delegateType"/> 类型的委托,表示静态或实例方法的委托。</returns>
        /// <remarks>支持参数的强制类型转换,参数声明可以与实际类型不同。方法不能是包含泛型参数的非泛型定义。</remarks>
        /// <exception cref="MethodAccessException">调用方无权访问 <paramref name="method"/>。</exception>
        private static Delegate CreateClosedDelegate(MethodBase method, Type delegateType, object firstArgument,
                                                     bool ensureClosed)
        {
            Contract.Requires(method != null && delegateType != null);
            if (!ensureClosed && firstArgument == null)
            {
                // 开放方法。
                Delegate dlg = CreateOpenDelegate(method, delegateType);
                if (dlg != null)
                {
                    return(dlg);
                }
            }
            // 封闭方法。
            MethodInfo invoke = delegateType.GetInvokeMethod();

            Type[] paramTypes             = invoke.GetParameterTypes();
            Type[] paramTypesWithFirstArg = paramTypes.Insert(0,
                                                              // 这里使用 firstArgument 的实际类型,因为需要做类型检查和泛型类型推断。
                                                              firstArgument == null ? null : firstArgument.GetType());
            // 判断是否需要作为实例的形参。
            int index = 0;

            if (!method.IsStatic && !(method is ConstructorInfo))
            {
                index++;
            }
            Type[] types      = paramTypesWithFirstArg.Extend(method.GetParametersNoCopy().Length + index, typeof(Missing));
            Type   returnType = invoke.ReturnType;
            MethodArgumentsInfo argumentsInfo = GetArgumentsInfo(ref method, types, returnType);

            if (argumentsInfo == null)
            {
                return(null);
            }
            bool needLoadFirstArg = false;

            if (!ILExt.CanEmitConstant(firstArgument))
            {
                needLoadFirstArg = true;
                // 修正额外参数的类型。
                Type argType = GetFirstArgParamType(method);
                // 提前进行类型转换。
                if (firstArgument != null && firstArgument.GetType() != argType)
                {
                    firstArgument = Convert.ChangeType(firstArgument, argType);
                }
                paramTypesWithFirstArg[0] = argType;
                paramTypes = paramTypesWithFirstArg;
            }
            // 构造动态委托。
            DynamicMethod dlgMethod = new DynamicMethod("MethodDelegate", returnType, paramTypes,
                                                        method.Module, true);
            ILGenerator il = dlgMethod.GetILGenerator();

            Contract.Assume(il != null);
            bool optimizeTailcall;

            if (needLoadFirstArg)
            {
                if (argumentsInfo.InstanceType != null)
                {
                    il.EmitLoadInstance(method, argumentsInfo.InstanceType, true);
                }
                optimizeTailcall = il.EmitLoadParameters(method, argumentsInfo, index);
            }
            else if (argumentsInfo.InstanceType != null)
            {
                il.EmitLoadInstance(method, firstArgument);
                optimizeTailcall = il.EmitLoadParameters(method, argumentsInfo, 0);
            }
            else
            {
                optimizeTailcall = il.EmitLoadParameters(method, argumentsInfo, firstArgument);
            }
            // 调用方法。
            Type[] optionalArgumentTypes = null;
            if (argumentsInfo.OptionalArgumentTypes != null)
            {
                optionalArgumentTypes = argumentsInfo.OptionalArgumentTypes.ToArray();
            }
            if (!il.EmitInvokeMethod(method, optionalArgumentTypes, returnType, optimizeTailcall))
            {
                return(null);
            }
            return(needLoadFirstArg ? dlgMethod.CreateDelegate(delegateType, firstArgument) : dlgMethod.CreateDelegate(delegateType));
        }
示例#5
0
        /// <summary>
        /// 加载方法参数。
        /// </summary>
        /// <param name="il">IL 指令生成器。</param>
        /// <param name="method">要加载参数的方法。</param>
        /// <param name="argumentsInfo">方法实参信息。</param>
        /// <param name="index">实参的起始索引。</param>
        /// <returns>能否对方法进行 tailcall 优化,如果可以则返回 <c>true</c>;否则返回 <c>false</c>。</returns>
        private static bool EmitLoadParameters(this ILGenerator il, MethodBase method, MethodArgumentsInfo argumentsInfo,
                                               int index)
        {
            Contract.Requires(il != null && method != null && argumentsInfo != null && index >= 0);
            ParameterInfo[] parameters       = method.GetParametersNoCopy();
            IList <Type>    args             = argumentsInfo.FixedArguments;
            int             argCnt           = args.Count;
            bool            optimizeTailcall = true;

            for (int i = 0; i < argCnt; i++, index++)
            {
                if (!il.EmitLoadParameter(parameters[i], index, args[i]))
                {
                    optimizeTailcall = false;
                }
            }
            if ((args = argumentsInfo.ParamArgumentTypes) != null)
            {
                // 加载 params 参数。
                argCnt = args.Count;
                Type elementType = argumentsInfo.ParamArrayType.GetElementType();
                Contract.Assume(elementType != null);
                il.EmitConstant(argCnt);
                il.Emit(OpCodes.Newarr, elementType);
                LocalBuilder local = il.GetLocal(argumentsInfo.ParamArrayType);
                il.Emit(OpCodes.Stloc, local);
                for (int i = 0; i < argCnt; i++, index++)
                {
                    il.Emit(OpCodes.Ldloc, local);
                    il.EmitConstant(i);
                    il.EmitLoadParameter(elementType, index, args[i]);
                    il.EmitStoreElement(elementType);
                }
                il.Emit(OpCodes.Ldloc, local);
                il.FreeLocal(local);
                optimizeTailcall = false;
            }
            else if ((args = argumentsInfo.OptionalArgumentTypes) != null)
            {
                // 加载可变参数。
                argCnt = args.Count;
                for (int i = 0; i < argCnt; i++, index++)
                {
                    il.EmitLoadParameter(args[i], index, args[i]);
                }
            }
            return(optimizeTailcall);
        }