コード例 #1
0
        /// <summary>
        /// 创建指定的静态或实例字段的指定类型的封闭字段委托。
        /// </summary>
        /// <param name="field">要获取或设置的字段。</param>
        /// <param name="delegateType">要创建的委托的类型。</param>
        /// <param name="firstArgument">如果是实例字段,则作为委托要绑定到的对象;否则将作为字段的第一个参数。</param>
        /// <returns><paramref name="delegateType"/> 类型的委托,表示静态或实例字段的委托。</returns>
        /// <remarks>如果委托具有返回值,则认为是获取字段,否则认为是设置字段。
        /// 支持参数的强制类型转换,参数声明可以与实际类型不同。</remarks>
        private static Delegate CreateClosedDelegate(FieldInfo field, Type delegateType, object firstArgument)
        {
            Contract.Requires(field != null && delegateType != null);
            if (firstArgument == null)
            {
                // 开放方法。
                Delegate dlg = CreateOpenDelegate(field, delegateType);
                if (dlg != null)
                {
                    return(dlg);
                }
            }
            // 提前对 firstArgument 进行类型转换。
            Type firstArgType = field.IsStatic ? field.FieldType : field.DeclaringType;

            Contract.Assume(firstArgType != null);
            if (firstArgument != null)
            {
                if (!firstArgType.IsExplicitFrom(firstArgument.GetType()))
                {
                    return(null);
                }
                firstArgument = Convert.ChangeType(firstArgument, firstArgType);
            }
            else if (firstArgType.IsValueType)
            {
                return(null);
            }
            MethodInfo invoke = delegateType.GetInvokeMethod();

            Type[] types            = invoke.GetParameterTypes();
            Type   returnType       = invoke.ReturnType;
            bool   needLoadFirstArg = false;

            if (!ILExt.CanEmitConstant(firstArgument))
            {
                // 需要添加作为实例的形参。
                needLoadFirstArg = true;
                // CreateDelegate 方法传入的 firstArgument 不能为值类型,除非形参类型是 object。
                types = types.Insert(0, firstArgType.IsValueType ? typeof(object) : firstArgType);
            }
            DynamicMethod dlgMethod = new DynamicMethod("FieldDelegate", returnType, types, field.Module, true);
            ILGenerator   il        = dlgMethod.GetILGenerator();

            if (needLoadFirstArg)
            {
                // 需要传入第一个参数。
                int index = 0;
                if (!field.IsStatic)
                {
                    if (!il.EmitFieldInstance(field, types))
                    {
                        return(null);
                    }
                    index++;
                }
                if (il.EmitAccessField(field, types, returnType, index))
                {
                    return(dlgMethod.CreateDelegate(delegateType, firstArgument));
                }
                return(null);
            }
            // 不需要传入第一个参数。
            if (field.IsStatic)
            {
                if (returnType != typeof(void))
                {
                    // firstArgument 非 null 的情况下,获取字段的值时参数不兼容。
                    return(null);
                }
                // 设置字段值。
                if (types.Length != 0)
                {
                    return(null);
                }
                il.EmitConstant(firstArgument);
                il.EmitStoreField(field);
                il.Emit(OpCodes.Ret);
            }
            else
            {
                il.EmitLoadInstance(field, firstArgument);
                if (!il.EmitAccessField(field, types, returnType, 0))
                {
                    return(null);
                }
            }
            return(dlgMethod.CreateDelegate(delegateType));
        }
コード例 #2
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));
        }