//读取方法信息,主要是方法的签名信息,名字+参数类型+返回值类型 static Dictionary <string, MethodMatchInfo[]> readMatchInfo(BinaryReader reader) { Dictionary <string, MethodMatchInfo[]> matchInfo = new Dictionary <string, MethodMatchInfo[]>(); int typeCount = reader.ReadInt32(); for (int k = 0; k < typeCount; k++) { string typeName = reader.ReadString(); int methodCount = reader.ReadInt32(); MethodMatchInfo[] methodMatchInfos = new MethodMatchInfo[methodCount]; for (int i = 0; i < methodCount; i++) { MethodMatchInfo mmi = new MethodMatchInfo(); mmi.Name = reader.ReadString(); mmi.ReturnType = reader.ReadString(); int parameterCount = reader.ReadInt32(); mmi.Parameters = new ParameterMatchInfo[parameterCount]; for (int p = 0; p < parameterCount; p++) { mmi.Parameters[p] = new ParameterMatchInfo(); mmi.Parameters[p].IsOut = reader.ReadBoolean(); mmi.Parameters[p].ParameterType = reader.ReadString(); } methodMatchInfos[i] = mmi; } matchInfo[typeName] = methodMatchInfos; } return(matchInfo); }
/// <summary> /// 基于参数类型,从给定的方法集中选择一个方法。 /// </summary> /// <param name="match">用于匹配的候选方法信息数组。</param> /// <param name="length">方法匹配信息的长度。</param> /// <param name="types">用于定位匹配方法的参数类型。</param> /// <returns>如果找到,则为匹配的方法信息;否则为 <c>null</c>。</returns> private MethodMatchInfo SelectMethod(MethodMatchInfo[] match, int length, Type[] types) { Contract.Requires(match != null && length >= 0 && types != null); if (length == 0) { // 没有可匹配的方法。 return(null); } if (length == 1) { // 只有一个可匹配的方法。 return(match[0]); } // 多个可匹配字段,尝试寻找类型最匹配的方法。 length = FilterMember(match, length, (firstMethod, secondMethod) => CompareMethod(firstMethod, secondMethod, types)); MethodMatchInfo best = match[0]; bool ambig = false; for (int i = 1; i < length; i++) { // 比较定义的层级深度。 int cmp = best.Method.DeclaringType.GetHierarchyDepth() - match[i].Method.DeclaringType.GetHierarchyDepth(); if (cmp == 0) { ambig = true; } else if (cmp < 0) { best = match[i]; ambig = false; } } return(ambig ? null : best); }
/// <summary> /// 基于参数类型,从给定的方法集中选择一个方法。 /// 允许通过指定 <see cref="BindingFlags.OptionalParamBinding"/> 来匹配可选参数。 /// </summary> /// <param name="bindingAttr"><see cref="BindingFlags"/> 值的按位组合。</param> /// <param name="match">用于匹配的候选方法集。</param> /// <param name="types">用于定位匹配方法的参数类型。</param> /// <param name="modifiers">使绑定能够处理在其中修改了类型的参数签名的参数修饰符数组。</param> /// <returns>如果找到,则为匹配的方法;否则为 <c>null</c>。</returns> /// <exception cref="ArgumentNullException"><paramref name="match"/> 为 <c>null</c>。</exception> /// <exception cref="ArgumentNullException"><paramref name="types"/> 为 <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="types"/> /// 匹配程度相同的方法。</exception> /// <remarks>此方法支持可选参数,可以通过为参数类型指定 <see cref="Missing"/> 来表示使用可选参数。 /// 或者为 <paramref name="bindingAttr"/> 设置 <see cref="BindingFlags.InvokeMethod"/>、 /// <see cref="BindingFlags.CreateInstance"/>、<see cref="BindingFlags.GetProperty"/> 或 /// <see cref="BindingFlags.SetProperty"/> 之一,就可以直接省略掉可选参数对应的类型。</remarks> public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers) { CommonExceptions.CheckCollectionItemNull(match, "match"); CommonExceptions.CheckArgumentNull(types, "types"); Contract.EndContractBlock(); MethodArgumentsOption options = MethodArgumentsOption.None; if (isExplicit) { options |= MethodArgumentsOption.Explicit; } if (bindingAttr.HasFlag(BindingFlags.OptionalParamBinding)) { options |= MethodArgumentsOption.OptionalParamBinding; } MethodMatchInfo[] infos = new MethodMatchInfo[match.Length]; MethodMatchInfo info; int length = 0; for (int i = 0; i < match.Length; i++) { info = MethodMatchInfo.GetMatchInfo(match[i], types, null, options); if (info != null) { infos[length++] = info; } } info = SelectMethod(infos, length, types); return(info == null ? null : info.Method); }
/// <summary> /// 更新参数数组。 /// </summary> /// <param name="match">被匹配的方法信息。</param> /// <param name="args">方法的参数。</param> /// <param name="state">旧的参数状态。</param> private static void UpdateArgs(MethodMatchInfo match, ref object[] args, out object state) { Contract.Requires(match != null && args != null); state = args; // 填充参数。 var parameters = match.FixedParameters; var fixedLen = parameters.Length; var length = fixedLen; Array paramArray = null; if (match.ParamArrayType != null) { length++; paramArray = Array.CreateInstance(match.ParamArrayElementType, args.Length - fixedLen); } var newArgs = new object[length].Fill(Missing.Value); if (paramArray != null) { newArgs[fixedLen] = paramArray; } var paramOrder = match.ParamOrder; for (var i = 0; i < args.Length; i++) { var idx = paramOrder == null ? i : paramOrder[i]; if (idx < fixedLen) { newArgs[idx] = args[i]; } else { Contract.Assume(paramArray != null); paramArray.SetValue(args[i], idx - fixedLen); } } // 填充默认值。 for (var i = 0; i < fixedLen; i++) { if (newArgs[i] != Missing.Value) { continue; } var param = parameters[i]; if (param.IsParamArray()) { newArgs[i] = Array.CreateInstance(param.ParameterType.GetElementType(), 0); } else { newArgs[i] = param.DefaultValue; } } args = newArgs; }
/// <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); }
/// <summary> /// 寻找与 <paramref name="types"/> 匹配的最好的方法。 /// </summary> /// <param name="firstMethod">要比较匹配的第一个方法。</param> /// <param name="secondMethod">要比较匹配的第二个方法。</param> /// <param name="types">要进行匹配的类型。</param> /// <returns>如果 <paramref name="firstMethod"/> 与 <paramref name="types"/> 匹配的更好,则返回一个负数; /// 如果 <paramref name="secondMethod"/> 与 <paramref name="types"/> 匹配的更好,则返回一个正数; /// 如果匹配程度相同,则为 <c>0</c>。</returns> /// <remarks>《CSharp Language Specification》 7.5.3.2 Better function member。</remarks> private int CompareMethod(MethodMatchInfo firstMethod, MethodMatchInfo secondMethod, Type[] types) { // 检查参数类型匹配。 int typeLen = types.Length; int cmpMethod = 0; for (int i = 0; i < typeLen; i++) { int cmp = CompareType(firstMethod.GetParameterType(i), secondMethod.GetParameterType(i), types[i]); if (cmpMethod == 0) { cmpMethod = cmp; } else if (cmp * cmpMethod < 0) { // 参数类型都有更好的。 return(0); } } if (cmpMethod != 0) { return(cmpMethod); } // 非泛型方法更好。 if (firstMethod.IsGeneric) { if (!secondMethod.IsGeneric) { return(1); } } else if (secondMethod.IsGeneric) { return(-1); } // 不展开 params 参数的方法比匹配。 if (firstMethod.ParamArrayType != null) { if (secondMethod.ParamArrayType == null) { return(1); } } else if (secondMethod.ParamArrayType != null) { return(-1); } // 有 params 参数时形参更多的更好,没有使用默认值的更好。 int firstLen = firstMethod.FixedParameters.Length; int secondLen = secondMethod.FixedParameters.Length; if (typeLen >= firstLen) { if (typeLen >= secondLen) { cmpMethod = secondLen - firstLen; if (cmpMethod != 0) { return(cmpMethod); } } else { return(-1); } } else if (typeLen >= secondLen) { return(1); } // 这里简单的比较泛型参数的个数,不将每个参数分别比较。 return(firstMethod.GenericArgumentLength - secondMethod.GenericArgumentLength); }