1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Microsoft Public License. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Microsoft Public License, please send an email to
8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Microsoft Public License.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
15 using System; using Microsoft;
18 using System.Collections.Generic;
20 using System.Dynamic.Utils;
21 using System.Linq.Expressions;
23 using Microsoft.Scripting.Utils;
24 using Microsoft.Linq.Expressions;
26 using System.Reflection;
27 using System.Runtime.Remoting;
30 namespace System.Dynamic {
32 namespace Microsoft.Scripting {
35 /// Represents the dynamic binding and a binding logic of an object participating in the dynamic binding.
37 public class DynamicMetaObject {
38 private readonly Expression _expression;
39 private readonly BindingRestrictions _restrictions;
40 private readonly object _value;
41 private readonly bool _hasValue;
44 /// Represents an empty array of type <see cref="DynamicMetaObject"/>. This field is read only.
46 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
47 public static readonly DynamicMetaObject[] EmptyMetaObjects = new DynamicMetaObject[0];
50 /// Initializes a new instance of the <see cref="DynamicMetaObject"/> class.
52 /// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param>
53 /// <param name="restrictions">The set of binding restrictions under which the binding is valid.</param>
54 public DynamicMetaObject(Expression expression, BindingRestrictions restrictions) {
55 ContractUtils.RequiresNotNull(expression, "expression");
56 ContractUtils.RequiresNotNull(restrictions, "restrictions");
58 _expression = expression;
59 _restrictions = restrictions;
63 /// Initializes a new instance of the <see cref="DynamicMetaObject"/> class.
65 /// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param>
66 /// <param name="restrictions">The set of binding restrictions under which the binding is valid.</param>
67 /// <param name="value">The runtime value represented by the <see cref="DynamicMetaObject"/>.</param>
68 public DynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value)
69 : this(expression, restrictions) {
75 /// The expression representing the <see cref="DynamicMetaObject"/> during the dynamic binding process.
77 public Expression Expression {
84 /// The set of binding restrictions under which the binding is valid.
86 public BindingRestrictions Restrictions {
93 /// The runtime value represented by this <see cref="DynamicMetaObject"/>.
102 /// Gets a value indicating whether the <see cref="DynamicMetaObject"/> has the runtime value.
104 public bool HasValue {
112 /// Gets the <see cref="Type"/> of the runtime value or null if the <see cref="DynamicMetaObject"/> has no value associated with it.
114 public Type RuntimeType {
117 Type ct = Expression.Type;
118 // valuetype at compile tyme, type cannot change.
119 if (ct.IsValueType) {
122 if (_value != null) {
123 return _value.GetType();
134 /// Gets the limit type of the <see cref="DynamicMetaObject"/>.
136 /// <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>
137 public Type LimitType {
139 return RuntimeType ?? Expression.Type;
144 /// Performs the binding of the dynamic conversion operation.
146 /// <param name="binder">An instance of the <see cref="ConvertBinder"/> that represents the details of the dynamic operation.</param>
147 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
148 public virtual DynamicMetaObject BindConvert(ConvertBinder binder) {
149 ContractUtils.RequiresNotNull(binder, "binder");
150 return binder.FallbackConvert(this);
154 /// Performs the binding of the dynamic get member operation.
156 /// <param name="binder">An instance of the <see cref="GetMemberBinder"/> that represents the details of the dynamic operation.</param>
157 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
158 public virtual DynamicMetaObject BindGetMember(GetMemberBinder binder) {
159 ContractUtils.RequiresNotNull(binder, "binder");
160 return binder.FallbackGetMember(this);
164 /// Performs the binding of the dynamic set member operation.
166 /// <param name="binder">An instance of the <see cref="SetMemberBinder"/> that represents the details of the dynamic operation.</param>
167 /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set member operation.</param>
168 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
169 public virtual DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) {
170 ContractUtils.RequiresNotNull(binder, "binder");
171 return binder.FallbackSetMember(this, value);
175 /// Performs the binding of the dynamic delete member operation.
177 /// <param name="binder">An instance of the <see cref="DeleteMemberBinder"/> that represents the details of the dynamic operation.</param>
178 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
179 public virtual DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) {
180 ContractUtils.RequiresNotNull(binder, "binder");
181 return binder.FallbackDeleteMember(this);
185 /// Performs the binding of the dynamic get index operation.
187 /// <param name="binder">An instance of the <see cref="GetIndexBinder"/> that represents the details of the dynamic operation.</param>
188 /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the get index operation.</param>
189 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
190 public virtual DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) {
191 ContractUtils.RequiresNotNull(binder, "binder");
192 return binder.FallbackGetIndex(this, indexes);
196 /// Performs the binding of the dynamic set index operation.
198 /// <param name="binder">An instance of the <see cref="SetIndexBinder"/> that represents the details of the dynamic operation.</param>
199 /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the set index operation.</param>
200 /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set index operation.</param>
201 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
202 public virtual DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) {
203 ContractUtils.RequiresNotNull(binder, "binder");
204 return binder.FallbackSetIndex(this, indexes, value);
208 /// Performs the binding of the dynamic delete index operation.
210 /// <param name="binder">An instance of the <see cref="DeleteIndexBinder"/> that represents the details of the dynamic operation.</param>
211 /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the delete index operation.</param>
212 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
213 public virtual DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes) {
214 ContractUtils.RequiresNotNull(binder, "binder");
215 return binder.FallbackDeleteIndex(this, indexes);
219 /// Performs the binding of the dynamic invoke member operation.
221 /// <param name="binder">An instance of the <see cref="InvokeMemberBinder"/> that represents the details of the dynamic operation.</param>
222 /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>
223 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
224 public virtual DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) {
225 ContractUtils.RequiresNotNull(binder, "binder");
226 return binder.FallbackInvokeMember(this, args);
230 /// Performs the binding of the dynamic invoke operation.
232 /// <param name="binder">An instance of the <see cref="InvokeBinder"/> that represents the details of the dynamic operation.</param>
233 /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke operation.</param>
234 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
235 public virtual DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) {
236 ContractUtils.RequiresNotNull(binder, "binder");
237 return binder.FallbackInvoke(this, args);
241 /// Performs the binding of the dynamic create instance operation.
243 /// <param name="binder">An instance of the <see cref="CreateInstanceBinder"/> that represents the details of the dynamic operation.</param>
244 /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the create instance operation.</param>
245 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
246 public virtual DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args) {
247 ContractUtils.RequiresNotNull(binder, "binder");
248 return binder.FallbackCreateInstance(this, args);
252 /// Performs the binding of the dynamic unary operation.
254 /// <param name="binder">An instance of the <see cref="UnaryOperationBinder"/> that represents the details of the dynamic operation.</param>
255 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
256 public virtual DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder) {
257 ContractUtils.RequiresNotNull(binder, "binder");
258 return binder.FallbackUnaryOperation(this);
262 /// Performs the binding of the dynamic binary operation.
264 /// <param name="binder">An instance of the <see cref="BinaryOperationBinder"/> that represents the details of the dynamic operation.</param>
265 /// <param name="arg">An instance of the <see cref="DynamicMetaObject"/> representing the right hand side of the binary operation.</param>
266 /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
267 public virtual DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg) {
268 ContractUtils.RequiresNotNull(binder, "binder");
269 return binder.FallbackBinaryOperation(this, arg);
273 /// Returns the enumeration of all dynamic member names.
275 /// <returns>The list of dynamic member names.</returns>
276 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
277 public virtual IEnumerable<string> GetDynamicMemberNames() {
278 return new string[0];
282 /// Returns the list of expressions represented by the <see cref="DynamicMetaObject"/> instances.
284 /// <param name="objects">An array of <see cref="DynamicMetaObject"/> instances to extract expressions from.</param>
285 /// <returns>The array of expressions.</returns>
286 internal static Expression[] GetExpressions(DynamicMetaObject[] objects) {
287 ContractUtils.RequiresNotNull(objects, "objects");
289 Expression[] res = new Expression[objects.Length];
290 for (int i = 0; i < objects.Length; i++) {
291 DynamicMetaObject mo = objects[i];
292 ContractUtils.RequiresNotNull(mo, "objects");
293 Expression expr = mo.Expression;
294 ContractUtils.RequiresNotNull(expr, "objects");
302 /// Creates a meta-object for the specified object.
304 /// <param name="value">The object to get a meta-object for.</param>
305 /// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param>
307 /// If the given object implements <see cref="IDynamicMetaObjectProvider"/> and is not a remote object from outside the current AppDomain,
308 /// returns the object's specific meta-object returned by <see cref="IDynamicMetaObjectProvider.GetMetaObject"/>. Otherwise a plain new meta-object
309 /// with no restrictions is created and returned.
311 public static DynamicMetaObject Create(object value, Expression expression) {
312 ContractUtils.RequiresNotNull(expression, "expression");
314 IDynamicMetaObjectProvider ido = value as IDynamicMetaObjectProvider;
316 if (ido != null && !RemotingServices.IsObjectOutOfAppDomain(value)) {
320 var idoMetaObject = ido.GetMetaObject(expression);
322 if (idoMetaObject == null ||
323 !idoMetaObject.HasValue ||
324 idoMetaObject.Value == null ||
325 (object)idoMetaObject.Expression != (object)expression) {
326 throw Error.InvalidMetaObjectCreated(ido.GetType());
329 return idoMetaObject;
331 return new DynamicMetaObject(expression, BindingRestrictions.Empty, value);