/// <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)); }
/// <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)); }