PageRenderTime 105ms CodeModel.GetById 60ms app.highlight 15ms RepoModel.GetById 25ms app.codeStats 0ms

/Microsoft.Scripting.Core/Actions/DynamicMetaObject.cs

https://bitbucket.org/stefanrusek/xronos
C# | 382 lines | 188 code | 39 blank | 155 comment | 21 complexity | ac866f8d19962fdbe1d25b382ef9f984 MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  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.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15using System; using Microsoft;
 16
 17
 18using System.Collections.Generic;
 19#if CODEPLEX_40
 20using System.Dynamic.Utils;
 21using System.Linq.Expressions;
 22#else
 23using Microsoft.Scripting.Utils;
 24using Microsoft.Linq.Expressions;
 25#endif
 26using System.Reflection;
 27using System.Runtime.Remoting;
 28
 29#if CODEPLEX_40
 30namespace System.Dynamic {
 31#else
 32namespace Microsoft.Scripting {
 33#endif
 34    /// <summary>
 35    /// Represents the dynamic binding and a binding logic of an object participating in the dynamic binding.
 36    /// </summary>
 37    public class DynamicMetaObject {
 38        private readonly Expression _expression;
 39        private readonly BindingRestrictions _restrictions;
 40        private readonly object _value;
 41        private readonly bool _hasValue;
 42
 43        /// <summary>
 44        /// Represents an empty array of type <see cref="DynamicMetaObject"/>. This field is read only.
 45        /// </summary>
 46        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
 47        public static readonly DynamicMetaObject[] EmptyMetaObjects = new DynamicMetaObject[0];
 48
 49        /// <summary>
 50        /// Initializes a new instance of the <see cref="DynamicMetaObject"/> class.
 51        /// </summary>
 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");
 57
 58            _expression = expression;
 59            _restrictions = restrictions;
 60        }
 61
 62        /// <summary>
 63        /// Initializes a new instance of the <see cref="DynamicMetaObject"/> class.
 64        /// </summary>
 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) {
 70            _value = value;
 71            _hasValue = true;
 72        }
 73
 74        /// <summary>
 75        /// The expression representing the <see cref="DynamicMetaObject"/> during the dynamic binding process.
 76        /// </summary>
 77        public Expression Expression {
 78            get {
 79                return _expression;
 80            }
 81        }
 82
 83        /// <summary>
 84        /// The set of binding restrictions under which the binding is valid.
 85        /// </summary>
 86        public BindingRestrictions Restrictions {
 87            get {
 88                return _restrictions;
 89            }
 90        }
 91
 92        /// <summary>
 93        /// The runtime value represented by this <see cref="DynamicMetaObject"/>.
 94        /// </summary>
 95        public object Value {
 96            get {
 97                return _value;
 98            }
 99        }
100
101        /// <summary>
102        /// Gets a value indicating whether the <see cref="DynamicMetaObject"/> has the runtime value.
103        /// </summary>
104        public bool HasValue {
105            get {
106                return _hasValue;
107            }
108        }
109
110
111        /// <summary>
112        /// Gets the <see cref="Type"/> of the runtime value or null if the <see cref="DynamicMetaObject"/> has no value associated with it.
113        /// </summary>
114        public Type RuntimeType {
115            get {
116                if (_hasValue) {
117                    Type ct = Expression.Type;
118                    // valuetype at compile tyme, type cannot change.
119                    if (ct.IsValueType) {
120                        return ct;
121                    }
122                    if (_value != null) {
123                        return _value.GetType();
124                    } else {
125                        return null;
126                    }
127                } else {
128                    return null;
129                }
130            }
131        }
132
133        /// <summary>
134        /// Gets the limit type of the <see cref="DynamicMetaObject"/>.
135        /// </summary>
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 {
138            get {
139                return RuntimeType ?? Expression.Type;
140            }
141        }
142
143        /// <summary>
144        /// Performs the binding of the dynamic conversion operation.
145        /// </summary>
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);
151        }
152
153        /// <summary>
154        /// Performs the binding of the dynamic get member operation.
155        /// </summary>
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);
161        }
162
163        /// <summary>
164        /// Performs the binding of the dynamic set member operation. 
165        /// </summary>
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);
172        }
173
174        /// <summary>
175        /// Performs the binding of the dynamic delete member operation.
176        /// </summary>
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);
182        }
183
184        /// <summary>
185        /// Performs the binding of the dynamic get index operation.
186        /// </summary>
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);
193        }
194
195        /// <summary>
196        /// Performs the binding of the dynamic set index operation.
197        /// </summary>
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);
205        }
206
207        /// <summary>
208        /// Performs the binding of the dynamic delete index operation.
209        /// </summary>
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);
216        }
217
218        /// <summary>
219        /// Performs the binding of the dynamic invoke member operation.
220        /// </summary>
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);
227        }
228
229        /// <summary>
230        /// Performs the binding of the dynamic invoke operation.
231        /// </summary>
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);
238        }
239
240        /// <summary>
241        /// Performs the binding of the dynamic create instance operation.
242        /// </summary>
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);
249        }
250
251        /// <summary>
252        /// Performs the binding of the dynamic unary operation.
253        /// </summary>
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);
259        }
260
261        /// <summary>
262        /// Performs the binding of the dynamic binary operation.
263        /// </summary>
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);
270        }
271
272        /// <summary>
273        /// Returns the enumeration of all dynamic member names.
274        /// </summary>
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];
279        }
280
281        /// <summary>
282        /// Returns the list of expressions represented by the <see cref="DynamicMetaObject"/> instances.
283        /// </summary>
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");
288
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");
295                res[i] = expr;
296            }
297
298            return res;
299        }
300
301        /// <summary>
302        /// Creates a meta-object for the specified object. 
303        /// </summary>
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>
306        /// <returns>
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.
310        /// </returns>
311        public static DynamicMetaObject Create(object value, Expression expression) {
312            ContractUtils.RequiresNotNull(expression, "expression");
313
314            IDynamicMetaObjectProvider ido = value as IDynamicMetaObjectProvider;
315#if !SILVERLIGHT
316            if (ido != null && !RemotingServices.IsObjectOutOfAppDomain(value)) {
317#else
318            if (ido != null) {
319#endif
320                var idoMetaObject = ido.GetMetaObject(expression);
321
322                if (idoMetaObject == null ||
323                    !idoMetaObject.HasValue ||
324                    idoMetaObject.Value == null ||
325                    (object)idoMetaObject.Expression != (object)expression) {
326                    throw Error.InvalidMetaObjectCreated(ido.GetType());
327                }
328
329                return idoMetaObject;
330            } else {
331                return new DynamicMetaObject(expression, BindingRestrictions.Empty, value);
332            }
333        }
334
335        /// <summary>
336        /// Creates a <see cref="DynamicMetaObject"/> to represent a binding exception.
337        /// </summary>
338        /// <param name="target">The target of dynamic operation whose binding failed.</param>
339        /// <param name="args">An array of arguments for the dynamic operation whose binding failed.</param>
340        /// <param name="exception">A type of the exception to be thrown to signal the binding failure.</param>
341        /// <param name="exceptionArgs">A list of arguments for the exception constructor.</param>
342        /// <returns>The new instance of <see cref="DynamicMetaObject"/> representing the binding error.</returns>
343        public static DynamicMetaObject CreateThrow(DynamicMetaObject target, DynamicMetaObject[] args, Type exception, params object[] exceptionArgs) {
344            return CreateThrow(
345                target,
346                args,
347                exception,
348                exceptionArgs != null ? exceptionArgs.Map<object, Expression>((arg) => Expression.Constant(arg)) : null
349            );
350        }
351
352        /// <summary>
353        /// Creates a <see cref="DynamicMetaObject"/> to represent a binding exception.
354        /// </summary>
355        /// <param name="target">The target of dynamic operation whose binding failed.</param>
356        /// <param name="args">An array of arguments for the dynamic operation whose binding failed.</param>
357        /// <param name="exception">A type of the exception to be thrown to signal the binding failure.</param>
358        /// <param name="exceptionArgs">A list of arguments for the exception constructor.</param>
359        /// <returns>The new instance of <see cref="DynamicMetaObject"/> representing the binding error.</returns>
360        public static DynamicMetaObject CreateThrow(DynamicMetaObject target, DynamicMetaObject[] args, Type exception, params Expression[] exceptionArgs) {
361            ContractUtils.RequiresNotNull(target, "target");
362            ContractUtils.RequiresNotNull(exception, "exception");
363
364            Type[] argTypes = exceptionArgs != null ? exceptionArgs.Map((arg) => arg.Type) : Type.EmptyTypes;
365            ConstructorInfo constructor = exception.GetConstructor(argTypes);
366
367            if (constructor == null) {
368                throw new ArgumentException(Strings.TypeDoesNotHaveConstructorForTheSignature);
369            }
370
371            return new DynamicMetaObject(
372                Expression.Throw(
373                    Expression.New(
374                        exception.GetConstructor(argTypes),
375                        exceptionArgs
376                    )
377                ),
378                target.Restrictions.Merge(BindingRestrictions.Combine(args))
379            );
380        }
381    }
382}