Пример #1
0
        //读取方法信息,主要是方法的签名信息,名字+参数类型+返回值类型
        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);
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        /// <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;
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        /// <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);
        }