ArgBuilder which provides a value for a keyword argument. The KeywordArgBuilder calculates its position at emit time using it's initial offset within the keyword arguments, the number of keyword arguments, and the total number of arguments provided by the user. It then delegates to an underlying ArgBuilder which only receives the single correct argument. Delaying the calculation of the position to emit time allows the method binding to be done without knowing the exact the number of arguments provided by the user. Hence, the method binder can be dependent only on the set of method overloads and keyword names, but not the user arguments. While the number of user arguments could be determined upfront, the current MethodBinder does not have this design.
Inheritance: ArgBuilder
Exemplo n.º 1
0
        public void MapParameter(ParameterInfo pi)
        {
            int indexForArgBuilder;
            int nameIndex = _argNames.IndexOf(pi.Name);

            if (nameIndex == -1)
            {
                // positional argument, we simply consume the next argument
                indexForArgBuilder = ArgIndex++;
            }
            else
            {
                // keyword argument, we just tell the simple arg builder to consume arg 0.
                // KeywordArgBuilder will then pass in the correct single argument based
                // upon the actual argument number provided by the user.
                indexForArgBuilder = 0;
            }

            // if the parameter is default we need to build a default arg builder and then
            // build a reduced method at the end.
            if (!pi.IsMandatory())
            {
                // We need to build the default builder even if we have a parameter for it already to
                // get good consistency of our error messages.  But consider a method like
                // def foo(a=1, b=2) and the user calls it as foo(b=3). Then adding the default
                // value breaks an otherwise valid call.  This is because we only generate MethodCandidates
                // filling in the defaults from right to left (so the method - 1 arg requires a,
                // and the method minus 2 args requires b).  So we only add the default if it's
                // a positional arg or we don't already have a default value.
                if (nameIndex == -1 || !_hasDefaults)
                {
                    _defaultArguments.Add(new DefaultArgBuilder(pi));
                    _hasDefaults = true;
                }
                else
                {
                    _defaultArguments.Add(null);
                }
            }
            else if (_defaultArguments.Count > 0)
            {
                // non-contigious default parameter
                _defaultArguments.Add(null);
            }

            ArgBuilder ab;

            if (pi.ParameterType.IsByRef)
            {
                _hasByRef = true;
                Type elementType = pi.ParameterType.GetElementType();
                Type refType     = typeof(StrongBox <>).MakeGenericType(elementType);
                _parameters.Add(new ParameterWrapper(pi, refType, pi.Name, ParameterBindingFlags.ProhibitNull));
                ab = new ReferenceArgBuilder(pi, elementType, refType, indexForArgBuilder);
            }
            else if (pi.Position == 0 && Overload.IsExtension)
            {
                _parameters.Add(new ParameterWrapper(pi, pi.ParameterType, pi.Name, ParameterBindingFlags.IsHidden));
                ab = new SimpleArgBuilder(pi, pi.ParameterType, indexForArgBuilder, false, false);
            }
            else
            {
                ab = AddSimpleParameterMapping(pi, indexForArgBuilder);
            }

            if (nameIndex == -1)
            {
                _arguments.Add(ab);
            }
            else
            {
                Debug.Assert(KeywordArgBuilder.BuilderExpectsSingleParameter(ab));
                _arguments.Add(new KeywordArgBuilder(ab, _argNames.Count, nameIndex));
            }
        }