1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Collections.Generic; 6 using System.Diagnostics; 7 using System.Dynamic.Utils; 8 using System.Linq.Expressions; 9 10 namespace System.Dynamic 11 { 12 /// <summary> 13 /// Represents the dynamic binding and a binding logic of an object participating in the dynamic binding. 14 /// </summary> 15 public class DynamicMetaObject 16 { 17 /// <summary> 18 /// Represents an empty array of type <see cref="DynamicMetaObject"/>. This field is read-only. 19 /// </summary> 20 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] 21 public static readonly DynamicMetaObject[] EmptyMetaObjects = Array.Empty<DynamicMetaObject>(); 22 23 /// <summary> 24 /// Initializes a new instance of the <see cref="DynamicMetaObject"/> class. 25 /// </summary> 26 /// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param> 27 /// <param name="restrictions">The set of binding restrictions under which the binding is valid.</param> DynamicMetaObject(Expression expression, BindingRestrictions restrictions)28 public DynamicMetaObject(Expression expression, BindingRestrictions restrictions) 29 { 30 ContractUtils.RequiresNotNull(expression, nameof(expression)); 31 ContractUtils.RequiresNotNull(restrictions, nameof(restrictions)); 32 33 Expression = expression; 34 Restrictions = restrictions; 35 } 36 37 /// <summary> 38 /// Initializes a new instance of the <see cref="DynamicMetaObject"/> class. 39 /// </summary> 40 /// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param> 41 /// <param name="restrictions">The set of binding restrictions under which the binding is valid.</param> 42 /// <param name="value">The runtime value represented by the <see cref="DynamicMetaObject"/>.</param> DynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value)43 public DynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value) 44 : this(expression, restrictions) 45 { 46 Value = value; 47 HasValue = true; 48 } 49 50 /// <summary> 51 /// The expression representing the <see cref="DynamicMetaObject"/> during the dynamic binding process. 52 /// </summary> 53 public Expression Expression { get; } 54 55 /// <summary> 56 /// The set of binding restrictions under which the binding is valid. 57 /// </summary> 58 public BindingRestrictions Restrictions { get; } 59 60 /// <summary> 61 /// The runtime value represented by this <see cref="DynamicMetaObject"/>. 62 /// </summary> 63 public object Value { get; } 64 65 /// <summary> 66 /// Gets a value indicating whether the <see cref="DynamicMetaObject"/> has the runtime value. 67 /// </summary> 68 public bool HasValue { get; } 69 70 /// <summary> 71 /// Gets the <see cref="Type"/> of the runtime value or null if the <see cref="DynamicMetaObject"/> has no value associated with it. 72 /// </summary> 73 public Type RuntimeType 74 { 75 get 76 { 77 if (HasValue) 78 { 79 Type ct = Expression.Type; 80 // valuetype at compile time, type cannot change. 81 if (ct.IsValueType) 82 { 83 return ct; 84 } 85 86 return Value?.GetType(); 87 } 88 else 89 { 90 return null; 91 } 92 } 93 } 94 95 /// <summary> 96 /// Gets the limit type of the <see cref="DynamicMetaObject"/>. 97 /// </summary> 98 /// <remarks>Represents the most specific type known about the object represented by the <see cref="DynamicMetaObject"/>. <see cref="RuntimeType"/> if runtime value is available, a type of the <see cref="Expression"/> otherwise.</remarks> 99 public Type LimitType => RuntimeType ?? Expression.Type; 100 101 /// <summary> 102 /// Performs the binding of the dynamic conversion operation. 103 /// </summary> 104 /// <param name="binder">An instance of the <see cref="ConvertBinder"/> that represents the details of the dynamic operation.</param> 105 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindConvert(ConvertBinder binder)106 public virtual DynamicMetaObject BindConvert(ConvertBinder binder) 107 { 108 ContractUtils.RequiresNotNull(binder, nameof(binder)); 109 return binder.FallbackConvert(this); 110 } 111 112 /// <summary> 113 /// Performs the binding of the dynamic get member operation. 114 /// </summary> 115 /// <param name="binder">An instance of the <see cref="GetMemberBinder"/> that represents the details of the dynamic operation.</param> 116 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindGetMember(GetMemberBinder binder)117 public virtual DynamicMetaObject BindGetMember(GetMemberBinder binder) 118 { 119 ContractUtils.RequiresNotNull(binder, nameof(binder)); 120 return binder.FallbackGetMember(this); 121 } 122 123 /// <summary> 124 /// Performs the binding of the dynamic set member operation. 125 /// </summary> 126 /// <param name="binder">An instance of the <see cref="SetMemberBinder"/> that represents the details of the dynamic operation.</param> 127 /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set member operation.</param> 128 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindSetMember(SetMemberBinder binder, DynamicMetaObject value)129 public virtual DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) 130 { 131 ContractUtils.RequiresNotNull(binder, nameof(binder)); 132 return binder.FallbackSetMember(this, value); 133 } 134 135 /// <summary> 136 /// Performs the binding of the dynamic delete member operation. 137 /// </summary> 138 /// <param name="binder">An instance of the <see cref="DeleteMemberBinder"/> that represents the details of the dynamic operation.</param> 139 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindDeleteMember(DeleteMemberBinder binder)140 public virtual DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) 141 { 142 ContractUtils.RequiresNotNull(binder, nameof(binder)); 143 return binder.FallbackDeleteMember(this); 144 } 145 146 /// <summary> 147 /// Performs the binding of the dynamic get index operation. 148 /// </summary> 149 /// <param name="binder">An instance of the <see cref="GetIndexBinder"/> that represents the details of the dynamic operation.</param> 150 /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the get index operation.</param> 151 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)152 public virtual DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) 153 { 154 ContractUtils.RequiresNotNull(binder, nameof(binder)); 155 return binder.FallbackGetIndex(this, indexes); 156 } 157 158 /// <summary> 159 /// Performs the binding of the dynamic set index operation. 160 /// </summary> 161 /// <param name="binder">An instance of the <see cref="SetIndexBinder"/> that represents the details of the dynamic operation.</param> 162 /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the set index operation.</param> 163 /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set index operation.</param> 164 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)165 public virtual DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) 166 { 167 ContractUtils.RequiresNotNull(binder, nameof(binder)); 168 return binder.FallbackSetIndex(this, indexes, value); 169 } 170 171 /// <summary> 172 /// Performs the binding of the dynamic delete index operation. 173 /// </summary> 174 /// <param name="binder">An instance of the <see cref="DeleteIndexBinder"/> that represents the details of the dynamic operation.</param> 175 /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the delete index operation.</param> 176 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes)177 public virtual DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes) 178 { 179 ContractUtils.RequiresNotNull(binder, nameof(binder)); 180 return binder.FallbackDeleteIndex(this, indexes); 181 } 182 183 /// <summary> 184 /// Performs the binding of the dynamic invoke member operation. 185 /// </summary> 186 /// <param name="binder">An instance of the <see cref="InvokeMemberBinder"/> that represents the details of the dynamic operation.</param> 187 /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param> 188 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)189 public virtual DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) 190 { 191 ContractUtils.RequiresNotNull(binder, nameof(binder)); 192 return binder.FallbackInvokeMember(this, args); 193 } 194 195 /// <summary> 196 /// Performs the binding of the dynamic invoke operation. 197 /// </summary> 198 /// <param name="binder">An instance of the <see cref="InvokeBinder"/> that represents the details of the dynamic operation.</param> 199 /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke operation.</param> 200 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)201 public virtual DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) 202 { 203 ContractUtils.RequiresNotNull(binder, nameof(binder)); 204 return binder.FallbackInvoke(this, args); 205 } 206 207 /// <summary> 208 /// Performs the binding of the dynamic create instance operation. 209 /// </summary> 210 /// <param name="binder">An instance of the <see cref="CreateInstanceBinder"/> that represents the details of the dynamic operation.</param> 211 /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the create instance operation.</param> 212 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args)213 public virtual DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args) 214 { 215 ContractUtils.RequiresNotNull(binder, nameof(binder)); 216 return binder.FallbackCreateInstance(this, args); 217 } 218 219 /// <summary> 220 /// Performs the binding of the dynamic unary operation. 221 /// </summary> 222 /// <param name="binder">An instance of the <see cref="UnaryOperationBinder"/> that represents the details of the dynamic operation.</param> 223 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindUnaryOperation(UnaryOperationBinder binder)224 public virtual DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder) 225 { 226 ContractUtils.RequiresNotNull(binder, nameof(binder)); 227 return binder.FallbackUnaryOperation(this); 228 } 229 230 /// <summary> 231 /// Performs the binding of the dynamic binary operation. 232 /// </summary> 233 /// <param name="binder">An instance of the <see cref="BinaryOperationBinder"/> that represents the details of the dynamic operation.</param> 234 /// <param name="arg">An instance of the <see cref="DynamicMetaObject"/> representing the right hand side of the binary operation.</param> 235 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns> BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)236 public virtual DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg) 237 { 238 ContractUtils.RequiresNotNull(binder, nameof(binder)); 239 return binder.FallbackBinaryOperation(this, arg); 240 } 241 242 /// <summary> 243 /// Returns the enumeration of all dynamic member names. 244 /// </summary> 245 /// <returns>The list of dynamic member names.</returns> 246 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] GetDynamicMemberNames()247 public virtual IEnumerable<string> GetDynamicMemberNames() => Array.Empty<string>(); 248 249 /// <summary> 250 /// Returns the list of expressions represented by the <see cref="DynamicMetaObject"/> instances. 251 /// </summary> 252 /// <param name="objects">An array of <see cref="DynamicMetaObject"/> instances to extract expressions from.</param> 253 /// <returns>The array of expressions.</returns> GetExpressions(DynamicMetaObject[] objects)254 internal static Expression[] GetExpressions(DynamicMetaObject[] objects) 255 { 256 ContractUtils.RequiresNotNull(objects, nameof(objects)); 257 258 Expression[] res = new Expression[objects.Length]; 259 for (int i = 0; i < objects.Length; i++) 260 { 261 DynamicMetaObject mo = objects[i]; 262 ContractUtils.RequiresNotNull(mo, nameof(objects)); 263 Expression expr = mo.Expression; 264 Debug.Assert(expr != null, "Unexpected null expression; ctor should have caught this."); 265 res[i] = expr; 266 } 267 268 return res; 269 } 270 271 /// <summary> 272 /// Creates a meta-object for the specified object. 273 /// </summary> 274 /// <param name="value">The object to get a meta-object for.</param> 275 /// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param> 276 /// <returns> 277 /// If the given object implements <see cref="IDynamicMetaObjectProvider"/> and is not a remote object from outside the current AppDomain, 278 /// returns the object's specific meta-object returned by <see cref="IDynamicMetaObjectProvider.GetMetaObject"/>. Otherwise a plain new meta-object 279 /// with no restrictions is created and returned. 280 /// </returns> Create(object value, Expression expression)281 public static DynamicMetaObject Create(object value, Expression expression) 282 { 283 ContractUtils.RequiresNotNull(expression, nameof(expression)); 284 285 IDynamicMetaObjectProvider ido = value as IDynamicMetaObjectProvider; 286 if (ido != null) 287 { 288 var idoMetaObject = ido.GetMetaObject(expression); 289 290 if (idoMetaObject == null || 291 !idoMetaObject.HasValue || 292 idoMetaObject.Value == null || 293 (object)idoMetaObject.Expression != (object)expression) 294 { 295 throw System.Linq.Expressions.Error.InvalidMetaObjectCreated(ido.GetType()); 296 } 297 298 return idoMetaObject; 299 } 300 else 301 { 302 return new DynamicMetaObject(expression, BindingRestrictions.Empty, value); 303 } 304 } 305 } 306 } 307