Пример #1
0
        public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion)
        {
            // First try COM binding.
            if (ComBinder.TryBindInvokeMember(this, target, args, out var result))
            {
                return(result);
            }

            // Defer if any object has no value so that we evaluate their Expressions and nest a
            // CallSite for the InvokeMember.
            if (!target.HasValue || Array.Exists(args, a => !a.HasValue))
            {
                var deferArgs = new DynamicMetaObject[args.Length + 1];
                deferArgs[0] = target;
                args.CopyTo(deferArgs.AsSpan(1));
                return(Defer(deferArgs));
            }

            // Find our own binding. Could consider allowing invoking static members from an instance.
            var members = target.LimitType.GetMember(Name, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);

            if (members.Length == 1 && (members[0] is PropertyInfo || members[0] is FieldInfo))
            {
                // NEED TO TEST, should check for delegate value too
                // var mem = members[0];
                throw new NotImplementedException();
                //return new DynamicMetaObject(
                //    Expression.Dynamic(
                //        new SymplInvokeBinder(new CallInfo(args.Length)),
                //        typeof(object),
                //        args.Select(a => a.Expression).AddFirst(
                //               Expression.MakeMemberAccess(this.Expression, mem)));

                // Don't test for eventinfos since we do nothing with them now.
            }
            else
            {
                // Get MethodInfos with param types that work for args. This works except for value
                // args that need to pass to reftype params. We could detect that to be smarter and
                // then explicitly StrongBox the args.
                var res = Array.FindAll(members, meth => meth is MethodInfo m && m.GetParameters().Length == args.Length && RuntimeHelpers.ParametersMatchArguments(m.GetParameters(), args));

                // False below means generate a type restriction on the MO. We are looking at the
                // members targetMO's Type.
                var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(target, args, false);
                if (res.Length == 0)
                {
                    return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args, restrictions,
                                                                         typeof(MissingMemberException), $"Can't bind member invoke -- {args}"));
                }

                // restrictions and conversion must be done consistently.
                var callArgs = RuntimeHelpers.ConvertArguments(args, ((MethodInfo)res[0]).GetParameters());
                return(new DynamicMetaObject(RuntimeHelpers.EnsureObjectResult(Expression.Call(Expression.Convert(target.Expression, target.LimitType), (MethodInfo)res[0], callArgs)), restrictions));
                // Could hve tried just letting expression.Call factory do the work, but if there is more
                // than one applicable method using just assignablefrom, expression.Call throws. It does
                // not pick a "most applicable" method or any method.
            }
        }
        public override DynamicMetaObject FallbackInvoke(
            DynamicMetaObject targetMO, DynamicMetaObject[] argMOs,
            DynamicMetaObject errorSuggestion)
        {
#if !NETSTANDARD
            // First try COM binding.
            DynamicMetaObject result;

            if (ComBinder.TryBindInvoke(this, targetMO, argMOs, out result))
            {
                return(result);
            }
#endif
            // Defer if any object has no value so that we evaulate their
            // Expressions and nest a CallSite for the InvokeMember.
            if (!targetMO.HasValue || argMOs.Any((a) => !a.HasValue))
            {
                var deferArgs = new DynamicMetaObject[argMOs.Length + 1];
                for (int i = 0; i < argMOs.Length; i++)
                {
                    deferArgs[i + 1] = argMOs[i];
                }
                deferArgs[0] = targetMO;
                return(Defer(deferArgs));
            }
            // Find our own binding.
            if (targetMO.LimitType.IsSubclassOf(typeof(Delegate)))
            {
                var parms = targetMO.LimitType.GetMethod("Invoke").GetParameters();
                if (parms.Length == argMOs.Length)
                {
                    // Don't need to check if argument types match parameters.
                    // If they don't, users get an argument conversion error.
                    var callArgs   = RuntimeHelpers.ConvertArguments(argMOs, parms);
                    var expression = Expression.Invoke(
                        Expression.Convert(targetMO.Expression, targetMO.LimitType),
                        callArgs);
                    return(new DynamicMetaObject(
                               RuntimeHelpers.EnsureObjectResult(expression),
                               BindingRestrictions.GetTypeRestriction(targetMO.Expression,
                                                                      targetMO.LimitType)));
                }
            }
            return(errorSuggestion ??
                   RuntimeHelpers.CreateThrow(
                       targetMO, argMOs,
                       BindingRestrictions.GetTypeRestriction(targetMO.Expression,
                                                              targetMO.LimitType),
                       typeof(InvalidOperationException),
                       "Wrong number of arguments for function -- " +
                       targetMO.LimitType.ToString() + " got " + argMOs.ToString()));
        }
Пример #3
0
        public override DynamicMetaObject FallbackCreateInstance(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion)
        {
            // Defer if any object has no value so that we evaluate their Expressions and nest a
            // CallSite for the InvokeMember.
            if (!target.HasValue || Array.Exists(args, a => !a.HasValue))
            {
                var deferArgs = new DynamicMetaObject[args.Length + 1];
                deferArgs[0] = target;
                args.CopyTo(deferArgs.AsSpan(1));

                return(Defer(deferArgs));
            }

            // Make sure target actually contains a Type.
            if (!typeof(Type).IsAssignableFrom(target.LimitType))
            {
                return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args, BindingRestrictions.Empty,
                                                                     typeof(InvalidOperationException),
                                                                     $"Type object must be used when creating instance -- {args}"));
            }

            var type = target.Value as Type;

            Debug.Assert(type is not null);
            var constructors = type.GetConstructors();
            // Get constructors with right arg counts.

            var res = Array.FindAll(constructors, c => c.GetParameters().Length == args.Length && RuntimeHelpers.ParametersMatchArguments(c.GetParameters(), args));

            // We generate an instance restriction on the target since it is a Type and the
            // constructor is associate with the actual Type instance.
            var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(target, args, true);

            if (res.Length == 0)
            {
                return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args, restrictions,
                                                                     typeof(MissingMemberException),
                                                                     $"Can't bind create instance -- {args}"));
            }

            var ctorArgs = RuntimeHelpers.ConvertArguments(args, res[0].GetParameters());

            return(new DynamicMetaObject(
                       // Creating an object, so don't need EnsureObjectResult.
                       Expression.New(res[0], ctorArgs), restrictions));
        }
Пример #4
0
        public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion)
        {
            // First try COM binding.
            if (ComBinder.TryBindInvoke(this, target, args, out var result))
            {
                return(result);
            }

            // Defer if any object has no value so that we evaulate their Expressions and nest a
            // CallSite for the InvokeMember.
            if (!target.HasValue || Array.Exists(args, a => !a.HasValue))
            {
                var deferArgs = new DynamicMetaObject[args.Length + 1];
                deferArgs[0] = target;
                args.CopyTo(deferArgs.AsSpan(1));
                return(Defer(deferArgs));
            }

            // Find our own binding.
            if (!target.LimitType.IsSubclassOf(typeof(Delegate)))
            {
                return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args,
                                                                     BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType),
                                                                     typeof(InvalidOperationException),
                                                                     $"Wrong number of arguments for function -- {target.LimitType} got {args}"));
            }

            var parameters = target.LimitType.GetMethod("Invoke") !.GetParameters();

            if (parameters.Length != args.Length)
            {
                return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args,
                                                                     BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType),
                                                                     typeof(InvalidOperationException),
                                                                     $"Wrong number of arguments for function -- {target.LimitType} got {args}"));
            }


            // Don't need to check if argument types match parameters. If they don't, users
            // get an argument conversion error.
            var callArgs   = RuntimeHelpers.ConvertArguments(args, parameters);
            var expression = Expression.Invoke(Expression.Convert(target.Expression, target.LimitType), callArgs);

            return(new DynamicMetaObject(RuntimeHelpers.EnsureObjectResult(expression), BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType)));
        }
Пример #5
0
        public override DynamicMetaObject BindCreateInstance(
            CreateInstanceBinder binder, DynamicMetaObject[] args)
        {
            var constructors = ReflType.GetConstructors();
            var ctors        = constructors.
                               Where(c => c.GetParameters().Length == args.Length);
            List <ConstructorInfo> res = new List <ConstructorInfo>();

            foreach (var c in ctors)
            {
                if (RuntimeHelpers.ParametersMatchArguments(c.GetParameters(),
                                                            args))
                {
                    res.Add(c);
                }
            }
            if (res.Count == 0)
            {
                // Binders won't know what to do with TypeModels, so pass the
                // RuntimeType they represent.  The binder might not be Sympl's.
                return(binder.FallbackCreateInstance(
                           RuntimeHelpers.GetRuntimeTypeMoFromModel(this),
                           args));
            }
            // For create instance of a TypeModel, we can create a instance
            // restriction on the MO, hence the true arg.
            var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(
                this, args, true);
            var ctorArgs =
                RuntimeHelpers.ConvertArguments(
                    args, res[0].GetParameters());

            return(new DynamicMetaObject(
                       // Creating an object, so don't need EnsureObjectResult.
                       Expression.New(res[0], ctorArgs),
                       restrictions));
        }
Пример #6
0
 public override DynamicMetaObject FallbackInvoke(
     DynamicMetaObject target, DynamicMetaObject[] args,
     DynamicMetaObject errorSuggestion)
 {
     // Defer if any object has no value so that we evaulate their
     // Expressions and nest a CallSite for the InvokeMember.
     if (!target.HasValue || args.Any(a => !a.HasValue))
     {
         return(Defer(target, args));
     }
     // Find our own binding.
     if (target.LimitType.IsSubclassOf(typeof(Delegate)))
     {
         var parms = target.LimitType.GetMethod("Invoke").GetParameters();
         if (parms.Length == args.Length)
         {
             // Don't need to check if argument types match parameters.
             // If they don't, users get an argument conversion error.
             var callArgs   = RuntimeHelpers.ConvertArguments(args, parms);
             var expression = Expression.Invoke(
                 Expression.Convert(target.Expression, target.LimitType),
                 callArgs);
             return(new DynamicMetaObject(
                        RuntimeHelpers.EnsureObjectResult(expression),
                        BindingRestrictions.GetTypeRestriction(target.Expression,
                                                               target.LimitType)));
         }
     }
     return(errorSuggestion ??
            RuntimeHelpers.CreateThrow(
                target, args,
                BindingRestrictions.GetTypeRestriction(target.Expression,
                                                       target.LimitType),
                typeof(InvalidOperationException),
                "Wrong number of arguments for function -- " +
                target.LimitType.ToString() + " got " + args.ToString()));
 }
Пример #7
0
        // Because we don't ComboBind over several MOs and operations, and no one
        // is falling back to this function with MOs that have no values, we
        // don't need to check HasValue.  If we did check, and HasValue == False,
        // then would defer to new InvokeMemberBinder.Defer().
        //
        public override DynamicMetaObject BindInvokeMember(
            InvokeMemberBinder binder, DynamicMetaObject[] args)
        {
            var flags = BindingFlags.IgnoreCase | BindingFlags.Static |
                        BindingFlags.Public;
            var members = ReflType.GetMember(binder.Name, flags);

            if ((members.Length == 1) && (members[0] is PropertyInfo ||
                                          members[0] is FieldInfo))
            {
                // NEED TO TEST, should check for delegate value too
                var mem = members[0];
                throw new NotImplementedException();
                //return new DynamicMetaObject(
                //    Expression.Dynamic(
                //        new SymplInvokeBinder(new CallInfo(args.Length)),
                //        typeof(object),
                //        args.Select(a => a.Expression).AddFirst(
                //               Expression.MakeMemberAccess(this.Expression, mem)));

                // Don't test for eventinfos since we do nothing with them now.
            }
            else
            {
                // Get MethodInfos with right arg counts.
                var mi_mems = members.
                              Select(m => m as MethodInfo).
                              Where(m => m is MethodInfo &&
                                    ((MethodInfo)m).GetParameters().Length ==
                                    args.Length);
                // Get MethodInfos with param types that work for args.  This works
                // for except for value args that need to pass to reftype params.
                // We could detect that to be smarter and then explicitly StrongBox
                // the args.
                List <MethodInfo> res = new List <MethodInfo>();
                foreach (var mem in mi_mems)
                {
                    if (RuntimeHelpers.ParametersMatchArguments(
                            mem.GetParameters(), args))
                    {
                        res.Add(mem);
                    }
                }
                if (res.Count == 0)
                {
                    // Sometimes when binding members on TypeModels the member
                    // is an intance member since the Type is an instance of Type.
                    // We fallback to the binder with the Type instance to see if
                    // it binds.  The SymplInvokeMemberBinder does handle this.
                    var typeMO = RuntimeHelpers.GetRuntimeTypeMoFromModel(this);
                    var result = binder.FallbackInvokeMember(typeMO, args, null);
                    return(result);
                }
                // True below means generate an instance restriction on the MO.
                // We are only looking at the members defined in this Type instance.
                var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(
                    this, args, true);
                // restrictions and conversion must be done consistently.
                var callArgs =
                    RuntimeHelpers.ConvertArguments(
                        args, res[0].GetParameters());
                return(new DynamicMetaObject(
                           RuntimeHelpers.EnsureObjectResult(
                               Expression.Call(res[0], callArgs)),
                           restrictions));
                // Could hve tried just letting Expr.Call factory do the work,
                // but if there is more than one applicable method using just
                // assignablefrom, Expr.Call throws.  It does not pick a "most
                // applicable" method or any method.
            }
        }
        public override DynamicMetaObject FallbackCreateInstance(
            DynamicMetaObject target,
            DynamicMetaObject[] args,
            DynamicMetaObject errorSuggestion)
        {
            // Defer if any object has no value so that we evaulate their
            // Expressions and nest a CallSite for the InvokeMember.
            if (!target.HasValue || args.Any((a) => !a.HasValue))
            {
                var deferArgs = new DynamicMetaObject[args.Length + 1];
                for (int i = 0; i < args.Length; i++)
                {
                    deferArgs[i + 1] = args[i];
                }
                deferArgs[0] = target;
                return(Defer(deferArgs));
            }
            // Make sure target actually contains a Type.
            if (!typeof(Type).IsAssignableFrom(target.LimitType))
            {
                return(errorSuggestion ??
                       RuntimeHelpers.CreateThrow(
                           target, args, BindingRestrictions.Empty,
                           typeof(InvalidOperationException),
                           "Type object must be used when creating instance -- " +
                           args.ToString()));
            }
            var type = target.Value as Type;

            Debug.Assert(type != null);
            var constructors = type.GetConstructors();
            // Get constructors with right arg counts.
            var ctors = constructors.
                        Where(c => c.GetParameters().Length == args.Length);
            List <ConstructorInfo> res = new List <ConstructorInfo>();

            foreach (var c in ctors)
            {
                if (RuntimeHelpers.ParametersMatchArguments(c.GetParameters(),
                                                            args))
                {
                    res.Add(c);
                }
            }
            // We generate an instance restriction on the target since it is a
            // Type and the constructor is associate with the actual Type instance.
            var restrictions =
                RuntimeHelpers.GetTargetArgsRestrictions(
                    target, args, true);

            if (res.Count == 0)
            {
                return(errorSuggestion ??
                       RuntimeHelpers.CreateThrow(
                           target, args, restrictions,
                           typeof(MissingMemberException),
                           "Can't bind create instance -- " + args.ToString()));
            }
            var ctorArgs =
                RuntimeHelpers.ConvertArguments(
                    args, res[0].GetParameters());

            return(new DynamicMetaObject(
                       // Creating an object, so don't need EnsureObjectResult.
                       Expression.New(res[0], ctorArgs),
                       restrictions));
        }
Пример #9
0
        public override DynamicMetaObject FallbackBinaryOperation(
            DynamicMetaObject target, DynamicMetaObject arg,
            DynamicMetaObject errorSuggestion)
        {
            // Defer if any object has no value so that we evaulate their
            // Expressions and nest a CallSite for the InvokeMember.
            if (!target.HasValue || !arg.HasValue)
            {
                return(Defer(target, arg));
            }
            var restrictions = target.Restrictions.Merge(arg.Restrictions);

            if (target.Value == null)
            {
                restrictions = restrictions.Merge(
                    BindingRestrictions.GetInstanceRestriction(target.Expression, null)
                    );
            }
            else
            {
                restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(
                                                      target.Expression, target.LimitType));
            }

            if (arg.Value == null)
            {
                restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction(
                                                      arg.Expression, null));
            }
            else
            {
                restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(
                                                      arg.Expression, arg.LimitType));
            }

            if (this.Operation == ExpressionType.Add)
            {
                if (target.LimitType == typeof(string) && arg.LimitType == typeof(string))
                {
                    return(new DynamicMetaObject(
                               RuntimeHelpers.EnsureObjectResult(Expression.Call(
                                                                     typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }),
                                                                     Expression.Convert(target.Expression, target.LimitType),
                                                                     Expression.Convert(arg.Expression, arg.LimitType))),
                               restrictions
                               ));
                }
                if (target.LimitType == typeof(DateTime))
                {
                    return(new DynamicMetaObject(
                               RuntimeHelpers.EnsureObjectResult(Expression.Call(
                                                                     typeof(BuiltInFunctions).GetMethod("DateAdd"),
                                                                     Expression.Constant("d"),
                                                                     Expression.Convert(arg.Expression, typeof(object)),
                                                                     target.Expression)),
                               restrictions
                               ));
                }
                else if (arg.LimitType == typeof(DateTime))
                {
                    return(new DynamicMetaObject(
                               Expression.Call(
                                   typeof(BuiltInFunctions).GetMethod("DateAdd"),
                                   Expression.Constant("d"),
                                   Expression.Convert(target.Expression, typeof(object)),
                                   arg.Expression),
                               restrictions
                               ));
                }
                else if (!target.LimitType.IsPrimitive || !arg.LimitType.IsPrimitive)
                {
                    DynamicMetaObject[] args = new DynamicMetaObject[] { target, arg };
                    List <MethodInfo>   res  = RuntimeHelpers.GetExtensionMethods("op_Addition", target, args);
                    if (res.Count > 0)
                    {
                        MethodInfo mi = null;
                        if (res.Count > 1)
                        {
                            //If more than one results found, attempt overload resolution
                            mi = RuntimeHelpers.ResolveOverload(res, args);
                        }
                        else
                        {
                            mi = res[0];
                        }

                        // restrictions and conversion must be done consistently.
                        var callArgs = RuntimeHelpers.ConvertArguments(args, mi.GetParameters());

                        return(new DynamicMetaObject(
                                   RuntimeHelpers.EnsureObjectResult(
                                       Expression.Call(null, mi, callArgs)
                                       ),
                                   restrictions
                                   ));
                    }
                }
            }

            if (target.LimitType.IsPrimitive && arg.LimitType.IsPrimitive)
            {
                Type       targetType;
                Expression first;
                Expression second;
                if (target.LimitType == arg.LimitType || target.LimitType.IsAssignableFrom(arg.LimitType))
                {
                    targetType = target.LimitType;
                    first      = Expression.Convert(target.Expression, targetType);
                    //if variable is object type, need to convert twice (unbox + convert)
                    second = Expression.Convert(
                        Expression.Convert(arg.Expression, arg.LimitType),
                        targetType
                        );
                }
                else
                {
                    targetType = arg.LimitType;
                    first      = Expression.Convert(
                        Expression.Convert(target.Expression, target.LimitType),
                        targetType
                        );
                    second = Expression.Convert(arg.Expression, targetType);
                }

                return(new DynamicMetaObject(
                           RuntimeHelpers.EnsureObjectResult(
                               Expression.MakeBinary(
                                   this.Operation,
                                   first,
                                   second
                                   )
                               ),
                           restrictions
                           ));
            }
            else
            {
                DynamicMetaObject[] args = null;
                MethodInfo          mi   = null;

                mi = typeof(HelperFunctions).GetMethod("BinaryOp");
                Expression        op  = Expression.Constant(this.Operation);
                DynamicMetaObject mop = new DynamicMetaObject(Expression.Constant(this.Operation), BindingRestrictions.Empty, this.Operation);

                args = new DynamicMetaObject[] { mop, target, arg };
                // restrictions and conversion must be done consistently.
                var callArgs = RuntimeHelpers.ConvertArguments(args, mi.GetParameters());

                return(new DynamicMetaObject(
                           RuntimeHelpers.EnsureObjectResult(
                               Expression.Call(
                                   mi,
                                   callArgs
                                   )
                               ),
                           restrictions
                           ));
            }
        }
Пример #10
0
        public override DynamicMetaObject FallbackInvokeMember(
            DynamicMetaObject targetMO, DynamicMetaObject[] args,
            DynamicMetaObject errorSuggestion)
        {
#if !NETSTANDARD
            // First try COM binding.
            DynamicMetaObject result;
            if (ComBinder.TryBindInvokeMember(this, targetMO, args, out result))
            {
                return(result);
            }
#endif
            // Defer if any object has no value so that we evaulate their
            // Expressions and nest a CallSite for the InvokeMember.
            if (!targetMO.HasValue || args.Any((a) => !a.HasValue))
            {
                var deferArgs = new DynamicMetaObject[args.Length + 1];
                for (int i = 0; i < args.Length; i++)
                {
                    deferArgs[i + 1] = args[i];
                }
                deferArgs[0] = targetMO;
                return(Defer(deferArgs));
            }
            // Find our own binding.
            // Could consider allowing invoking static members from an instance.
            var flags = BindingFlags.IgnoreCase | BindingFlags.Instance |
                        BindingFlags.Public;
            var members = targetMO.LimitType.GetMember(this.Name, flags);

            var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(
                targetMO, args, false);

            // Assigned a Null
            if (targetMO.HasValue && targetMO.Value == null)
            {
                return(RuntimeHelpers.CreateThrow(targetMO,
                                                  args,
                                                  restrictions,
                                                  typeof(NullReferenceException),
                                                  "Object reference not set to an instance of an object."));
            }

            if ((members.Length == 1) && (members[0] is PropertyInfo ||
                                          members[0] is FieldInfo))
            {
                // NEED TO TEST, should check for delegate value too
                var mem    = members[0];
                var target = new DynamicMetaObject(
                    RuntimeHelpers.EnsureObjectResult(
                        Expression.MakeMemberAccess(
                            Expression.Convert(targetMO.Expression,
                                               members[0].DeclaringType),
                            members[0])),
                    // Don't need restriction test for name since this
                    // rule is only used where binder is used, which is
                    // only used in sites with this binder.Name.
                    BindingRestrictions.GetTypeRestriction(targetMO.Expression,
                                                           targetMO.LimitType));

                //If no arguments, to allow scenario like Request.QueryString()
                if (args == null || args.Length == 0)
                {
                    return(target);
                }

                return(new DynamicMetaObject(
                           RuntimeHelpers.GetIndexingExpression(target, args),
                           restrictions
                           ));
                // Don't test for eventinfos since we do nothing with them now.
            }
            else
            {
                bool isExtension = false;

                // Get MethodInfos with right arg counts.
                var mi_mems = members.
                              Select(m => m as MethodInfo).
                              Where(m => m is MethodInfo &&
                                    ((MethodInfo)m).GetParameters().Length ==
                                    args.Length);
                // Get MethodInfos with param types that work for args.  This works
                // except for value args that need to pass to reftype params.
                // We could detect that to be smarter and then explicitly StrongBox
                // the args.
                List <MethodInfo> res = new List <MethodInfo>();
                foreach (var mem in mi_mems)
                {
                    if (RuntimeHelpers.ParametersMatchArguments(
                            mem.GetParameters(), args))
                    {
                        res.Add(mem);
                    }
                }

                List <DynamicMetaObject> argList = new List <DynamicMetaObject>(args);

                //Try extension methods if no methods found
                if (res.Count == 0)
                {
                    isExtension = true;
                    argList.Insert(0, targetMO);

                    res = RuntimeHelpers.GetExtensionMethods(this.Name, targetMO, argList.ToArray());
                }

                // False below means generate a type restriction on the MO.
                // We are looking at the members targetMO's Type.
                if (res.Count == 0)
                {
                    return(errorSuggestion ??
                           RuntimeHelpers.CreateThrow(
                               targetMO, args, restrictions,
                               typeof(MissingMemberException),
                               string.Format("Can't bind member invoke {0}.{1}({2})", targetMO.RuntimeType.Name, this.Name, args.ToString())));
                }

                //If more than one results found, attempt overload resolution
                MethodInfo mi = null;
                if (res.Count > 1)
                {
                    mi = RuntimeHelpers.ResolveOverload(res, argList.ToArray());
                }
                else
                {
                    mi = res[0];
                }

                // restrictions and conversion must be done consistently.
                var callArgs = RuntimeHelpers.ConvertArguments(
                    argList.ToArray(), mi.GetParameters());

                if (isExtension)
                {
                    return(new DynamicMetaObject(
                               RuntimeHelpers.EnsureObjectResult(
                                   Expression.Call(
                                       null,
                                       mi, callArgs)),
                               restrictions));
                }
                else
                {
                    return(new DynamicMetaObject(
                               RuntimeHelpers.EnsureObjectResult(
                                   Expression.Call(
                                       Expression.Convert(targetMO.Expression,
                                                          targetMO.LimitType),
                                       mi, callArgs)),
                               restrictions));
                }
                // Could hve tried just letting Expr.Call factory do the work,
                // but if there is more than one applicable method using just
                // assignablefrom, Expr.Call throws.  It does not pick a "most
                // applicable" method or any method.
            }
        }
Пример #11
0
        public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject targetMO, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
        {
            // Defer if any object has no value so that we evaulate their
            // Expressions and nest a CallSite for the InvokeMember.
            if (!targetMO.HasValue || args.Any(a => !a.HasValue))
            {
                var deferArgs = new DynamicMetaObject[args.Length + 1];
                for (int i = 0; i < args.Length; i++)
                {
                    deferArgs[i + 1] = args[i];
                }
                deferArgs[0] = targetMO;
                return(Defer(deferArgs));
            }
            // Find our own binding.
            // Could consider allowing invoking static members from an instance.
            const BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Instance |
                                       BindingFlags.Public;
            var members = targetMO.LimitType.GetMember(Name, flags);

            if ((members.Length == 1) && (members[0] is PropertyInfo ||
                                          members[0] is FieldInfo))
            {
                // NEED TO TEST, should check for delegate value too
                throw new NotImplementedException();
            }
            // Get MethodInfos with right arg counts.
            var miMems = members.
                         Select(m => m as MethodInfo).
                         Where(m => m.GetParameters().Length == args.Length);
            // Get MethodInfos with param types that work for args.  This works
            // except for value args that need to pass to reftype params.
            // We could detect that to be smarter and then explicitly StrongBox
            // the args.
            var res = new List <MethodInfo>();

            foreach (var mem in miMems)
            {
                if (RuntimeHelpers.ParametersMatchArguments(
                        mem.GetParameters(), args))
                {
                    res.Add(mem);
                }
            }
            // False below means generate a type restriction on the MO.
            // We are looking at the members targetMO's Type.
            var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(
                targetMO, args, false);

            if (res.Count == 0)
            {
                return(errorSuggestion ??
                       RuntimeHelpers.CreateThrow(
                           targetMO, args, restrictions,
                           typeof(MissingMemberException),
                           "Can't bind member invoke -- " + args.ToString()));
            }
            // restrictions and conversion must be done consistently.
            var callArgs = RuntimeHelpers.ConvertArguments(
                args, res[0].GetParameters());

            return(new DynamicMetaObject(
                       RuntimeHelpers.EnsureObjectResult(
                           Expression.Call(
                               Expression.Convert(targetMO.Expression,
                                                  targetMO.LimitType),
                               res[0], callArgs)),
                       restrictions));
            // Could hve tried just letting Expr.Call factory do the work,
            // but if there is more than one applicable method using just
            // assignablefrom, Expr.Call throws.  It does not pick a "most
            // applicable" method or any method.
        }