Example #1
0
        public override DynamicMetaObject FallbackGetIndex(
            DynamicMetaObject target, DynamicMetaObject[] indexes,
            DynamicMetaObject errorSuggestion)
        {
#if !SILVERLIGHT
            // First try COM binding.
            DynamicMetaObject result;
            if (ComBinder.TryBindGetIndex(this, target, indexes, 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 (!target.HasValue || indexes.Any((a) => !a.HasValue))
            {
                var deferArgs = new DynamicMetaObject[indexes.Length + 1];
                for (int i = 0; i < indexes.Length; i++)
                {
                    deferArgs[i + 1] = indexes[i];
                }
                deferArgs[0] = target;
                return(Defer(deferArgs));
            }

            var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(
                target, indexes, false);

            if (target.HasValue && target.Value == null)
            {
                return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target,
                                                                     indexes,
                                                                     restrictions,
                                                                     typeof(NullReferenceException),
                                                                     "Object reference not set to an instance of an object."));
            }
            var indexingExpr = RuntimeHelpers.EnsureObjectResult(
                RuntimeHelpers.GetIndexingExpression(target,
                                                     indexes));
            return(new DynamicMetaObject(indexingExpr, restrictions));
        }
        public override DynamicMetaObject FallbackGetIndex(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject?errorSuggestion)
        {
            // First try COM binding.
            if (ComBinder.TryBindGetIndex(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));
            }

            // Give good error for Cons.
            if (target.LimitType == typeof(Cons))
            {
                if (args.Length != 1)
                {
                    return(errorSuggestion ?? RuntimeHelpers.CreateThrow(target, args, BindingRestrictions.Empty,
                                                                         typeof(InvalidOperationException),
                                                                         $"Indexing list takes single index. Got {args.Length}"));
                }
            }

            // Find our own binding.
            // Conversions created in GetIndexExpression must be consistent with restrictions made in GetTargetArgsRestrictions.
            var indexingExpr = RuntimeHelpers.EnsureObjectResult(RuntimeHelpers.GetIndexingExpression(target, args));
            var restrictions = RuntimeHelpers.GetTargetArgsRestrictions(target, args, false);

            return(new DynamicMetaObject(indexingExpr, restrictions));
        }
Example #3
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.
            }
        }