public static Create ( object value, |
||
value | object | The object to get a meta-object for. |
expression | The expression representing this |
|
return |
private static DynamicMetaObject[] CreateArgumentMetaObjects(object[] args, ReadOnlyCollection <ParameterExpression> parameters) { if (args.Length != 1) { DynamicMetaObject[] objArray = new DynamicMetaObject[args.Length - 1]; for (int i = 1; i < args.Length; i++) { objArray[i - 1] = DynamicMetaObject.Create(args[i], parameters[i]); } return(objArray); } return(DynamicMetaObject.EmptyMetaObjects); }
private static DynamicMetaObject[] CreateArgumentMetaObjects(object[] args, ReadOnlyCollection<ParameterExpression> parameters) { DynamicMetaObject[] mos; if (args.Length != 1) { mos = new DynamicMetaObject[args.Length - 1]; for (int i = 1; i < args.Length; i++) { mos[i - 1] = DynamicMetaObject.Create(args[i], parameters[i]); } } else { mos = DynamicMetaObject.EmptyMetaObjects; } return mos; }
/// <summary> /// Performs the runtime binding of the dynamic operation on a set of arguments. /// </summary> /// <param name="args">An array of arguments to the dynamic operation.</param> /// <param name="parameters">The array of <see cref="ParameterExpression"/> instances that represent the parameters of the call site in the binding process.</param> /// <param name="returnLabel">A LabelTarget used to return the result of the dynamic binding.</param> /// <returns> /// An Expression that performs tests on the dynamic operation arguments, and /// performs the dynamic operation if the tests are valid. If the tests fail on /// subsequent occurrences of the dynamic operation, Bind will be called again /// to produce a new <see cref="Expression"/> for the new argument types. /// </returns> public sealed override Expression Bind(object[] args, ReadOnlyCollection <ParameterExpression> parameters, LabelTarget returnLabel) { ContractUtils.RequiresNotNull(args, nameof(args)); ContractUtils.RequiresNotNull(parameters, nameof(parameters)); ContractUtils.RequiresNotNull(returnLabel, nameof(returnLabel)); if (args.Length == 0) { throw System.Linq.Expressions.Error.OutOfRange("args.Length", 1); } if (parameters.Count == 0) { throw System.Linq.Expressions.Error.OutOfRange("parameters.Count", 1); } if (args.Length != parameters.Count) { throw new ArgumentOutOfRangeException(nameof(args)); } // Ensure that the binder's ReturnType matches CallSite's return // type. We do this so meta objects and language binders can // compose trees together without needing to insert converts. Type expectedResult; if (IsStandardBinder) { expectedResult = ReturnType; if (returnLabel.Type != typeof(void) && !TypeUtils.AreReferenceAssignable(returnLabel.Type, expectedResult)) { throw System.Linq.Expressions.Error.BinderNotCompatibleWithCallSite(expectedResult, this, returnLabel.Type); } } else { // Even for non-standard binders, we have to at least make sure // it works with the CallSite's type to build the return. expectedResult = returnLabel.Type; } DynamicMetaObject target = DynamicMetaObject.Create(args[0], parameters[0]); DynamicMetaObject[] metaArgs = CreateArgumentMetaObjects(args, parameters); DynamicMetaObject binding = Bind(target, metaArgs); if (binding == null) { throw System.Linq.Expressions.Error.BindingCannotBeNull(); } Expression body = binding.Expression; BindingRestrictions restrictions = binding.Restrictions; // Ensure the result matches the expected result type. if (expectedResult != typeof(void) && !TypeUtils.AreReferenceAssignable(expectedResult, body.Type)) { // // Blame the last person that handled the result: assume it's // the dynamic object (if any), otherwise blame the language. // if (target.Value is IDynamicMetaObjectProvider) { throw System.Linq.Expressions.Error.DynamicObjectResultNotAssignable(body.Type, target.Value.GetType(), this, expectedResult); } else { throw System.Linq.Expressions.Error.DynamicBinderResultNotAssignable(body.Type, this, expectedResult); } } // if the target is IDO, standard binders ask it to bind the rule so we may have a target-specific binding. // it makes sense to restrict on the target's type in such cases. // ideally IDO metaobjects should do this, but they often miss that type of "this" is significant. if (IsStandardBinder && args[0] as IDynamicMetaObjectProvider != null) { if (restrictions == BindingRestrictions.Empty) { throw System.Linq.Expressions.Error.DynamicBindingNeedsRestrictions(target.Value.GetType(), this); } } // Add the return if (body.NodeType != ExpressionType.Goto) { body = Expression.Return(returnLabel, body); } // Finally, add restrictions if (restrictions != BindingRestrictions.Empty) { body = Expression.IfThen(restrictions.ToExpression(), body); } return(body); }
/// <inheritdoc /> /// <summary> /// Performs the runtime binding of the dynamic operation on a set of arguments. /// </summary> /// <param name="args">An array of arguments to the dynamic operation.</param> /// <param name="parameters"> /// The array of <see cref="T:System.Linq.Expressions.ParameterExpression" /> instances that represent the parameters /// of the /// call site in the binding process. /// </param> /// <param name="returnLabel">A LabelTarget used to return the result of the dynamic binding.</param> /// <returns> /// An Expression that performs tests on the dynamic operation arguments, and /// performs the dynamic operation if the tests are valid. If the tests fail on /// subsequent occurrences of the dynamic operation, Bind will be called again /// to produce a new <see cref="T:System.Linq.Expressions.Expression" /> for the new argument types. /// </returns> public sealed override Expression Bind(object[] args, ReadOnlyCollection <ParameterExpression> parameters, LabelTarget returnLabel) { ContractUtils.RequiresNotNull(args, nameof(args)); ContractUtils.RequiresNotNull(parameters, nameof(parameters)); ContractUtils.RequiresNotNull(returnLabel, nameof(returnLabel)); if (args.Length == 0) { throw new ArgumentOutOfRangeException(nameof(args), "args.Length must be greater than or equal to 1"); } if (parameters.Count == 0) { throw new ArgumentOutOfRangeException(nameof(parameters), "parameters.Count must be greater than or equal to 1"); } if (args.Length != parameters.Count) { throw new ArgumentOutOfRangeException(nameof(args)); } // Ensure that the binder's ReturnType matches CallSite's return // type. We do this so meta objects and language binders can // compose trees together without needing to insert converts. Type expectedResult; if (IsStandardBinder) { expectedResult = ReturnType; if (returnLabel.Type != typeof(void) && !returnLabel.Type.IsReferenceAssignableFromInternal(expectedResult)) { throw new InvalidOperationException($"The result type '{expectedResult}' of the binder '{this}' is not compatible with the result type '{returnLabel.Type}' expected by the call site."); } } else { // Even for non-standard binders, we have to at least make sure // it works with the CallSite's type to build the return. expectedResult = returnLabel.Type; } var target = DynamicMetaObject.Create(args[0], parameters[0]); var metaArgs = CreateArgumentMetaObjects(args, parameters); var binding = Bind(target, metaArgs); if (binding == null) { throw new InvalidOperationException("Bind cannot return null."); } var body = binding.Expression; var restrictions = binding.Restrictions; // Ensure the result matches the expected result type. if (expectedResult != typeof(void) && !expectedResult.IsReferenceAssignableFromInternal(body.Type)) { // // Blame the last person that handled the result: assume it's // the dynamic object (if any), otherwise blame the language. // if (target.Value is IDynamicMetaObjectProvider) { throw new InvalidCastException($"The result type '{body.Type}' of the dynamic binding produced by the object with type '{target.Value.GetType()}' for the binder '{this}' is not compatible with the result type '{expectedResult}' expected by the call site."); } throw new InvalidCastException($"The result type '{body.Type}' of the dynamic binding produced by binder '{this}' is not compatible with the result type '{expectedResult}' expected by the call site."); } // if the target is IDO, standard binders ask it to bind the rule so we may have a target-specific binding. // it makes sense to restrict on the target's type in such cases. // ideally IDO meta-objects should do this, but they often miss that type of "this" is significant. if (IsStandardBinder && args[0] is IDynamicMetaObjectProvider && restrictions == BindingRestrictions.Empty) { throw new InvalidOperationException($"The result of the dynamic binding produced by the object with type '{target.Value.GetType()}' for the binder '{this}' needs at least one restriction."); } // Add the return if (body.NodeType != ExpressionType.Goto) { body = Expression.Return(returnLabel, body); } // Finally, add restrictions if (restrictions != BindingRestrictions.Empty) { body = Expression.IfThen(restrictions.ToExpression(), body); } return(body); }
public sealed override Expression Bind(object[] args, ReadOnlyCollection <ParameterExpression> parameters, LabelTarget returnLabel) { Type returnType; ContractUtils.RequiresNotNull(args, "args"); ContractUtils.RequiresNotNull(parameters, "parameters"); ContractUtils.RequiresNotNull(returnLabel, "returnLabel"); if (args.Length == 0) { throw Error.OutOfRange("args.Length", 1); } if (parameters.Count == 0) { throw Error.OutOfRange("parameters.Count", 1); } if (args.Length != parameters.Count) { throw new ArgumentOutOfRangeException("args"); } if (this.IsStandardBinder) { returnType = this.ReturnType; if ((returnLabel.Type != typeof(void)) && !TypeUtils.AreReferenceAssignable(returnLabel.Type, returnType)) { throw Error.BinderNotCompatibleWithCallSite(returnType, this, returnLabel.Type); } } else { returnType = returnLabel.Type; } DynamicMetaObject target = DynamicMetaObject.Create(args[0], parameters[0]); DynamicMetaObject[] objArray = CreateArgumentMetaObjects(args, parameters); DynamicMetaObject obj3 = this.Bind(target, objArray); if (obj3 == null) { throw Error.BindingCannotBeNull(); } Expression expression = obj3.Expression; BindingRestrictions restrictions = obj3.Restrictions; if ((returnType != typeof(void)) && !TypeUtils.AreReferenceAssignable(returnType, expression.Type)) { if (target.Value is IDynamicMetaObjectProvider) { throw Error.DynamicObjectResultNotAssignable(expression.Type, target.Value.GetType(), this, returnType); } throw Error.DynamicBinderResultNotAssignable(expression.Type, this, returnType); } if ((this.IsStandardBinder && (args[0] is IDynamicMetaObjectProvider)) && (restrictions == BindingRestrictions.Empty)) { throw Error.DynamicBindingNeedsRestrictions(target.Value.GetType(), this); } restrictions = AddRemoteObjectRestrictions(restrictions, args, parameters); if (expression.NodeType != ExpressionType.Goto) { expression = Expression.Return(returnLabel, expression); } if (restrictions != BindingRestrictions.Empty) { expression = Expression.IfThen(restrictions.ToExpression(), expression); } return(expression); }