/// <summary> /// 基于参数类型,从给定的方法集中选择一个方法。 /// 允许通过指定 <see cref="BindingFlags.OptionalParamBinding"/> 来匹配可选参数。 /// </summary> /// <param name="bindingAttr"><see cref="System.Reflection.BindingFlags"/> 值的按位组合。</param> /// <param name="infos">用于匹配的候选方法信息集。</param> /// <param name="len">方法信息集合的长度。</param> /// <param name="types">用于定位匹配方法的参数类型。</param> /// <returns>如果找到,则为匹配的方法信息;否则为 <c>null</c>。</returns> private MatchInfo SelectMethod(BindingFlags bindingAttr, MatchInfo[] infos, int len, Type[] types) { bool optionalParamBinding = (bindingAttr & BindingFlags.OptionalParamBinding) != 0; int idx = 0; for (int i = 0; i < len; i++) { MatchInfo info = infos[i]; Type paramArrayType; if (MethodExt.CheckParameterCount(info.Parameters, types, info.ParamOrder, optionalParamBinding, out paramArrayType)) { info.ParamArrayType = paramArrayType; if (MakeGenericMethod(info, types) && CheckParameterType(info, types, optionalParamBinding)) { infos[idx++] = info; } } } if (idx == 0) { // 没有可匹配的方法。 return(null); } else if (idx == 1) { // 只有一个可匹配的方法。 return(infos[0]); } // 多个可匹配方法,寻找匹配的最好的方法。 int min = 0; bool ambig = false; for (int i = 1; i < idx; i++) { int cmp = FindMostSpecificMethod(infos[min], infos[i], types); if (cmp == 0) { ambig = true; } else if (cmp == 2) { min = i; ambig = false; } } if (ambig) { throw CommonExceptions.AmbiguousMatchMethod(); } return(infos[min]); }
/// <summary> /// 基于提供的参数,从给定的方法集中选择要调用的方法。 /// </summary> /// <param name="bindingAttr"><see cref="BindingFlags"/> 值的按位组合。</param> /// <param name="match">用于匹配的候选方法集。</param> /// <param name="args">传入的参数。</param> /// <param name="modifiers">使绑定能够处理在其中修改了类型的参数签名的参数修饰符数组。</param> /// <param name="culture">一个 <see cref="CultureInfo"/> 实例, /// 用于在强制类型的联编程序实现中控制数据类型强制。</param> /// <param name="names">参数名(如果匹配时要考虑参数名)或 <c>null</c>(如果要将变量视为纯位置)。</param> /// <param name="state">方法返回之后,<paramref name="state"/> 包含一个联编程序提供的对象, /// 用于跟踪参数的重新排序。</param> /// <returns>匹配的方法。</returns> /// <exception cref="ArgumentNullException"><paramref name="match"/> 为 <c>null</c>。</exception> /// <exception cref="ArgumentNullException"><paramref name="args"/> 为 <c>null</c>。</exception> /// <exception cref="ArgumentException"><paramref name="match"/> 为空数组。</exception> /// <exception cref="ArgumentException"><paramref name="match"/> 中包含为 <c>null</c> 的元素。</exception> /// <exception cref="AmbiguousMatchException"><paramref name="match"/> 包含多个与 <paramref name="args"/> /// 匹配程度相同的方法。</exception> /// <exception cref="MissingFieldException"><paramref name="bindingAttr"/> 包含 /// <see cref="BindingFlags.SetField"/>,且 <paramref name="match"/> 不包含任何可接受 <paramref name="args"/> /// 的方法。</exception> public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state) { CommonExceptions.CheckCollectionItemNull(match, "match"); CommonExceptions.CheckArgumentNull(args, "args"); if (names != null && names.Length > args.Length) { throw CommonExceptions.NamedParamTooBig("names"); } Contract.EndContractBlock(); // 检查参数名称数组,不能出现名称相同的参数。 if (names != null && !names.IsDistinct(StringComparer.Ordinal)) { throw CommonExceptions.DuplicateName("names"); } MethodArgumentsOption options = MethodArgumentsOption.None; if (isExplicit) { options |= MethodArgumentsOption.Explicit; } if (bindingAttr.HasFlag(BindingFlags.OptionalParamBinding)) { options |= MethodArgumentsOption.OptionalParamBinding; } int typesLen = args.Length; Type[] types = new Type[typesLen]; for (int i = 0; i < typesLen; i++) { object arg = args[i]; types[i] = arg == null ? null : arg.GetType(); } MethodMatchInfo[] infos = new MethodMatchInfo[match.Length]; MethodMatchInfo info; int length = 0; for (int i = 0; i < match.Length; i++) { int[] paramOrder = null; if (names != null) { paramOrder = CreateParamOrder(match[i], names, typesLen); if (paramOrder == null) { continue; } } info = MethodMatchInfo.GetMatchInfo(match[i], types, paramOrder, options); if (info != null) { infos[length++] = info; } } if (length == 0) { // 没有可匹配的方法。 state = null; throw CommonExceptions.MissingMethod(); } info = SelectMethod(infos, length, types); if (info == null) { state = null; throw CommonExceptions.AmbiguousMatchMethod(); } UpdateArgs(info, ref args, out state); return(info.Method); }