/// <summary> /// 返回指定方法的匹配信息。 /// </summary> /// <param name="method">要进行匹配的方法。</param> /// <param name="types">方法的预期参数列表,使用 <c>null</c> 表示引用类型约束,<see cref="Missing"/> /// 表示使用默认值。</param> /// <param name="paramOrder">方法的参数顺序列表,使用 <c>paramOrder[i]</c> 表示 <c>indexes[i]</c> /// 的实际参数位置,其长度大于等于 <paramref name="types"/> 的长度。如果为 <c>null</c> 则表示使用默认顺序。</param> /// <param name="options">方法参数的选项。</param> /// <returns><paramref name="method"/> 的匹配信息,如果不能进行匹配则为 <c>null</c>。</returns> public static MethodMatchInfo GetMatchInfo(MethodBase method, Type[] types, int[] paramOrder, MethodArgumentsOption options) { Contract.Requires(method != null && types != null); Contract.Requires(paramOrder == null || paramOrder.Length >= types.Length); // 修正 indexes 的格式。 var parameters = method.GetParametersNoCopy(); if (paramOrder == null) { types = types.Extend(parameters.Length, typeof(Missing)); } else { var typeLen = types.Length; var newTypes = new Type[typeLen > parameters.Length ? typeLen : parameters.Length]; newTypes.Fill(typeof(Missing)); for (var i = 0; i < typeLen; i++) { newTypes[paramOrder[i]] = types[i]; } types = newTypes; } MethodArgumentsInfo argsInfo; // 对泛型方法进行泛型类型推断。 if (method.IsGenericMethodDefinition) { var declaringType = method.DeclaringType; if (declaringType != null && declaringType.ContainsGenericParameters) { return(null); } argsInfo = method.GenericArgumentsInferences(null, types, options); if (argsInfo == null) { return(null); } method = ((MethodInfo)method).MakeGenericMethod(argsInfo.GenericArguments); argsInfo.UpdateParamArrayType(method); } else { argsInfo = MethodArgumentsInfo.GetInfo(method, types, options); } if (argsInfo == null) { return(null); } if (argsInfo.OptionalArgumentTypes != null) { // 动态调用不支持可变参数。 return(null); } return(new MethodMatchInfo(method, argsInfo, paramOrder)); }
/// <summary> /// 使用指定的方法信息初始化 <see cref="MethodMatchInfo"/> 结构的新实例。 /// </summary> /// <param name="method">方法信息。</param> /// <param name="argsInfo">方法实参信息。</param> /// <param name="paramOrder">参数顺序。</param> private MethodMatchInfo(MethodBase method, MethodArgumentsInfo argsInfo, int[] paramOrder) { Contract.Requires(method != null); this.Method = method; if (method.IsGenericMethod) { this.IsGeneric = method.IsGenericMethod; this.GenericArgumentLength = method.GetGenericArguments().Length; } this.FixedParameters = method.GetParametersNoCopy().Left(argsInfo.FixedArguments.Count); this.ParamArrayType = argsInfo.ParamArrayType; if (this.ParamArrayType != null) { this.ParamArrayElementType = this.ParamArrayType.GetElementType(); } this.ParamOrder = paramOrder; }
/// <summary> /// 返回方法的参数信息。 /// </summary> /// <param name="method">要获取参数信息的方法。</param> /// <param name="types">方法实参类型数组,其长度必须大于等于方法的参数个数。 /// 使用 <see cref="Missing"/> 表示无需进行类型检查,<c>null</c> 表示引用类型标志。</param> /// <param name="options">方法参数信息的选项。</param> /// <returns>方法的参数信息。</returns> public static MethodArgumentsInfo GetInfo(MethodBase method, Type[] types, MethodArgumentsOption options) { Contract.Requires(method != null && types != null); MethodArgumentsInfo result = new MethodArgumentsInfo(method, types); bool optionalParamBinding = options.HasFlag(MethodArgumentsOption.OptionalParamBinding); bool isExplicit = options.HasFlag(MethodArgumentsOption.Explicit); bool convertRefType = options.HasFlag(MethodArgumentsOption.ConvertRefType); // 填充方法实例。 int offset = 0; if (options.HasFlag(MethodArgumentsOption.ContainsInstance)) { if (!result.MarkInstanceType(isExplicit, convertRefType)) { return(null); } offset++; } // 填充 params 参数和可变参数。 if (!result.FillParamArray(isExplicit, convertRefType)) { return(null); } // 检查实参是否与形参对应,未对应的参数是否包含默认值。 ParameterInfo[] parameters = method.GetParametersNoCopy(); int paramLen = parameters.Length; if (result.ParamArrayType != null) { paramLen--; Contract.Assume(paramLen >= 0); } for (int i = 0, j = offset; i < paramLen; i++, j++) { if (!CheckParameter(parameters[i], types[j], optionalParamBinding, isExplicit, convertRefType)) { return(null); } } result.fixedArguments = new ArrayAdapter <Type>(types, offset, paramLen); return(result); }
/// <summary> /// 根据给定的方法实参类型数组推断泛型方法的泛型类型。 /// </summary> /// <param name="method">要推断泛型类型的泛型方法定义。</param> /// <param name="returnType">方法的实际返回类型,如果不存在则传入 <c>null</c>。</param> /// <param name="types">方法实参类型数组。</param> /// <param name="options">方法参数信息的选项。</param> /// <returns>如果成功推断泛型方法的类型参数,则为推断结果;否则为 <c>null</c>。</returns> /// <remarks>得到的结果中,<see cref="MethodArgumentsInfo.ParamArrayType"/> 可能包含泛型类型参数。</remarks> internal static MethodArgumentsInfo GenericArgumentsInferences(this MethodBase method, Type returnType, Type[] types, MethodArgumentsOption options) { Contract.Requires(method != null && types != null); ParameterInfo[] parameters = method.GetParametersNoCopy(); // 提取方法参数信息。 types = types.Extend(parameters.Length, typeof(Missing)); MethodArgumentsInfo result = MethodArgumentsInfo.GetInfo(method, types, options); if (result == null) { return(null); } // 对方法返回值进行推断。 bool isExplicit = options.HasFlag(MethodArgumentsOption.Explicit); TypeBounds bounds = new TypeBounds(method.GetGenericArguments()); if (!CheckReturnType(method, returnType, bounds, isExplicit)) { return(null); } // 对方法固定参数进行推断。 int paramLen = result.FixedArguments.Count; for (int i = 0; i < paramLen; i++) { Type paramType = parameters[i].ParameterType; Type argType = result.FixedArguments[i]; if (paramType.ContainsGenericParameters && argType != typeof(Missing) && !bounds.TypeInferences(paramType, argType)) { return(null); } } IList <Type> paramArgTypes = result.ParamArgumentTypes; if (result.ParamArrayType == null || paramArgTypes.Count == 0) { Type[] args = bounds.FixTypeArguments(); if (args == null) { return(null); } result.GenericArguments = args; return(result); } // 对 params 参数进行推断。 Type paramElementType = result.ParamArrayType.GetElementType(); int paramArgCnt = paramArgTypes.Count; if (paramArgCnt > 1) { // 多个实参对应一个形参,做多次类型推断。 for (int i = 0; i < paramArgCnt; i++) { if (paramArgTypes[i] != typeof(Missing) && !bounds.TypeInferences(paramElementType, paramArgTypes[i])) { return(null); } } Type[] args = bounds.FixTypeArguments(); if (args == null) { return(null); } result.GenericArguments = args; return(result); } // 一个实参对应一个形参,需要判断是否需要展开 params 参数。 TypeBounds newBounds = new TypeBounds(bounds); Type type = paramArgTypes[0]; // 首先尝试对 paramArrayType 进行推断。 if (type == typeof(Missing) || bounds.TypeInferences(result.ParamArrayType, type)) { Type[] args = bounds.FixTypeArguments(); if (args != null) { // 推断成功的话,则无需展开 params 参数。 result.ClearParamArrayType(); result.GenericArguments = args; return(result); } } // 然后尝试对 paramElementType 进行推断。 if (newBounds.TypeInferences(paramElementType, type)) { Type[] args = newBounds.FixTypeArguments(); if (args == null) { return(null); } result.GenericArguments = args; return(result); } return(null); }
/// <summary> /// 返回方法的参数信息。 /// </summary> /// <param name="method">要获取参数信息的方法。</param> /// <param name="types">方法实参类型数组,其长度必须大于等于方法的参数个数。 /// 使用 <see cref="Missing"/> 表示无需进行类型检查,<c>null</c> 表示引用类型标志。</param> /// <param name="options">方法参数信息的选项。</param> /// <returns>方法的参数信息。</returns> public static MethodArgumentsInfo GetInfo(MethodBase method, Type[] types, MethodArgumentsOption options) { Contract.Requires(method != null && types != null); MethodArgumentsInfo result = new MethodArgumentsInfo(method, types); bool optionalParamBinding = options.HasFlag(MethodArgumentsOption.OptionalParamBinding); bool isExplicit = options.HasFlag(MethodArgumentsOption.Explicit); bool convertRefType = options.HasFlag(MethodArgumentsOption.ConvertRefType); // 填充方法实例。 int offset = 0; if (options.HasFlag(MethodArgumentsOption.ContainsInstance)) { if (!result.MarkInstanceType(isExplicit, convertRefType)) { return null; } offset++; } // 填充 params 参数和可变参数。 if (!result.FillParamArray(isExplicit, convertRefType)) { return null; } // 检查实参是否与形参对应,未对应的参数是否包含默认值。 ParameterInfo[] parameters = method.GetParametersNoCopy(); int paramLen = parameters.Length; if (result.ParamArrayType != null) { paramLen--; Contract.Assume(paramLen >= 0); } for (int i = 0, j = offset; i < paramLen; i++, j++) { if (!CheckParameter(parameters[i], types[j], optionalParamBinding, isExplicit, convertRefType)) { return null; } } result.fixedArguments = new ArrayAdapter<Type>(types, offset, paramLen); return result; }