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