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) .Merge(BindingRestrictions.GetTypeRestriction( target.Expression, target.LimitType)) .Merge(BindingRestrictions.GetTypeRestriction( arg.Expression, arg.LimitType)); return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult( Expression.MakeBinary( Operation, Expression.Convert(target.Expression, target.LimitType), Expression.Convert(arg.Expression, arg.LimitType))), restrictions )); }
public override DynamicMetaObject BindGetMember(GetMemberBinder binder) { var flags = BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Public; // consider BindingFlags.Instance if want to return wrapper for // inst members that is callable. var members = ReflType.GetMember(binder.Name, flags); if (members.Length == 1) { return(new DynamicMetaObject( // We always access static members for type model objects, so the // first argument in MakeMemberAccess should be null. RuntimeHelpers.EnsureObjectResult( Expression.MakeMemberAccess( null, 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. this.Restrictions.Merge( BindingRestrictions.GetInstanceRestriction( this.Expression, this.Value) ) )); } else { return(binder.FallbackGetMember(this)); } }
public override DynamicMetaObject FallbackUnaryOperation( DynamicMetaObject target, 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) { return(Defer(target)); } var restrictions = target.Restrictions; if (target.Value == null) { restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, null) ); } else { restrictions = restrictions.Merge( BindingRestrictions.GetTypeRestriction( target.Expression, target.LimitType)); } if (this.Operation == ExpressionType.Not) { if (target.LimitType != typeof(bool)) { MethodInfo mi = typeof(HelperFunctions).GetMethod("Not"); return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult( Expression.Call(mi, target.Expression) ), restrictions)); } } else if (this.Operation == ExpressionType.Negate) { if (!target.LimitType.IsPrimitive || target.LimitType == typeof(bool)) { MethodInfo mi = typeof(HelperFunctions).GetMethod("Negate"); return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult( Expression.Call(mi, target.Expression) ), restrictions)); } } return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult( Expression.MakeUnary( this.Operation, Expression.Convert(target.Expression, target.LimitType), target.LimitType)), restrictions)); }
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 FallbackUnaryOperation(DynamicMetaObject target, DynamicMetaObject?errorSuggestion) => // Defer if any object has no value so that we evaluate their Expressions and nest a // CallSite for the InvokeMember. target.HasValue ? new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult(Expression.MakeUnary(Operation, Expression.Convert(target.Expression, target.LimitType), target.LimitType)), target.Restrictions.Merge( BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))) : Defer(target);
protected internal override Expression Eval(Context scope) { scope.ReturnLabel = Expression.Label(typeof(object)); if (_returnExpression != null) { var ret = Expression.Return(scope.ReturnLabel, RuntimeHelpers.EnsureObjectResult(_returnExpression.Eval(scope)), typeof(object)); return(ret); } return(Expression.Return(scope.ReturnLabel, Expression.Constant(true))); }
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())); }
public override DynamicMetaObject FallbackGetMember( DynamicMetaObject targetMO, DynamicMetaObject errorSuggestion) { #if !SILVERLIGHT // First try COM binding. DynamicMetaObject result; if (ComBinder.TryBindGetMember(this, targetMO, 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) { return(Defer(targetMO)); } // Find our own binding. var flags = BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public; var members = targetMO.LimitType.GetMember(this.Name, flags); if (members.Length == 1) { return(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))); } else { return(errorSuggestion ?? RuntimeHelpers.CreateThrow( targetMO, null, BindingRestrictions.GetTypeRestriction(targetMO.Expression, targetMO.LimitType), typeof(MissingMemberException), "cannot bind member, " + this.Name + ", on object " + targetMO.Value.ToString())); } }
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))); }
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)); }
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())); }
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 )); } }
// 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 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. }
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. } }
public override DynamicMetaObject FallbackSetMember( DynamicMetaObject targetMO, DynamicMetaObject value, DynamicMetaObject errorSuggestion) { #if !NETSTANDARD // First try COM binding. DynamicMetaObject result; if (ComBinder.TryBindSetMember(this, targetMO, value, 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) { return(Defer(targetMO)); } // Find our own binding. var flags = BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public; var members = targetMO.LimitType.GetMember(this.Name, flags); if (members.Length == 1) { MemberInfo mem = members[0]; Expression val; // Should check for member domain type being Type and value being // TypeModel, similar to ConvertArguments, and building an // expression like GetRuntimeTypeMoFromModel. if (mem.MemberType == MemberTypes.Property) { val = Expression.Convert(value.Expression, ((PropertyInfo)mem).PropertyType); } else if (mem.MemberType == MemberTypes.Field) { val = Expression.Convert(value.Expression, ((FieldInfo)mem).FieldType); } else { return(errorSuggestion ?? RuntimeHelpers.CreateThrow( targetMO, null, BindingRestrictions.GetTypeRestriction( targetMO.Expression, targetMO.LimitType), typeof(InvalidOperationException), "Sympl only supports setting Properties and " + "fields at this time.")); } return(new DynamicMetaObject( // Assign returns the stored value, so we're good for Sympl. RuntimeHelpers.EnsureObjectResult( Expression.Assign( Expression.MakeMemberAccess( Expression.Convert(targetMO.Expression, members[0].DeclaringType), members[0]), val)), // 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))); } else { return(errorSuggestion ?? RuntimeHelpers.CreateThrow( targetMO, null, BindingRestrictions.GetTypeRestriction(targetMO.Expression, targetMO.LimitType), typeof(MissingMemberException), "IDynObj member name conflict.")); } }