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