BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / ListInitExpression.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. \r
4  *\r
5  * This source code is subject to terms and conditions of the Apache License, Version 2.0. A \r
6  * copy of the license can be found in the License.html file at the root of this distribution. If \r
7  * you cannot locate the  Apache License, Version 2.0, please send an email to \r
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound \r
9  * by the terms of the Apache License, Version 2.0.\r
10  *\r
11  * You must not remove this notice, or any other, from this software.\r
12  *\r
13  *\r
14  * ***************************************************************************/\r
15 \r
16 using System;\r
17 using System.Collections.Generic;\r
18 using System.Collections.ObjectModel;\r
19 using System.Diagnostics;\r
20 using System.Dynamic.Utils;\r
21 using System.Reflection;\r
22 using System.Runtime.CompilerServices;\r
23 \r
24 #if SILVERLIGHT\r
25 using System.Core;\r
26 #endif\r
27 \r
28 #if CLR2\r
29 namespace Microsoft.Scripting.Ast {\r
30 #else\r
31 namespace System.Linq.Expressions {\r
32 #endif\r
33     /// <summary>\r
34     /// Represents a constructor call that has a collection initializer.\r
35     /// </summary>\r
36     /// <remarks>\r
37     /// Use the <see cref="M:ListInit"/> factory methods to create a ListInitExpression. \r
38     /// The value of the NodeType property of a ListInitExpression is ListInit. \r
39     /// </remarks>\r
40 #if !SILVERLIGHT\r
41     [DebuggerTypeProxy(typeof(Expression.ListInitExpressionProxy))]\r
42 #endif\r
43     public sealed class ListInitExpression : Expression {\r
44         private readonly NewExpression _newExpression;\r
45         private readonly ReadOnlyCollection<ElementInit> _initializers;\r
46 \r
47         internal ListInitExpression(NewExpression newExpression, ReadOnlyCollection<ElementInit> initializers) {\r
48             _newExpression = newExpression;\r
49             _initializers = initializers;\r
50         }\r
51 \r
52         /// <summary>\r
53         /// Returns the node type of this <see cref="Expression"/>. (Inherited from <see cref="Expression" />.)\r
54         /// </summary>\r
55         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>\r
56         public sealed override ExpressionType NodeType {\r
57             get { return ExpressionType.ListInit; }\r
58         }\r
59 \r
60         /// <summary>\r
61         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)\r
62         /// </summary>\r
63         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>\r
64         public sealed override Type Type {\r
65             get { return _newExpression.Type; }\r
66         }\r
67 \r
68         /// <summary>\r
69         /// Gets a value that indicates whether the expression tree node can be reduced. \r
70         /// </summary>\r
71         public override bool CanReduce {\r
72             get {\r
73                 return true;\r
74             }\r
75         }\r
76 \r
77         /// <summary>\r
78         /// Gets the expression that contains a call to the constructor of a collection type. \r
79         /// </summary>\r
80         public NewExpression NewExpression {\r
81             get { return _newExpression; }\r
82         }\r
83 \r
84         /// <summary>\r
85         /// Gets the element initializers that are used to initialize a collection. \r
86         /// </summary>\r
87         public ReadOnlyCollection<ElementInit> Initializers {\r
88             get { return _initializers; }\r
89         }\r
90 \r
91         /// <summary>\r
92         /// Dispatches to the specific visit method for this node type.\r
93         /// </summary>\r
94         protected internal override Expression Accept(ExpressionVisitor visitor) {\r
95             return visitor.VisitListInit(this);\r
96         }\r
97 \r
98         /// <summary>\r
99         /// Reduces the binary expression node to a simpler expression. \r
100         /// If CanReduce returns true, this should return a valid expression.\r
101         /// This method is allowed to return another node which itself \r
102         /// must be reduced.\r
103         /// </summary>\r
104         /// <returns>The reduced expression.</returns>\r
105         public override Expression Reduce() {\r
106             return MemberInitExpression.ReduceListInit(_newExpression, _initializers, true);\r
107         }\r
108 \r
109         /// <summary>\r
110         /// Creates a new expression that is like this one, but using the\r
111         /// supplied children. If all of the children are the same, it will\r
112         /// return this expression.\r
113         /// </summary>\r
114         /// <param name="newExpression">The <see cref="NewExpression" /> property of the result.</param>\r
115         /// <param name="initializers">The <see cref="Initializers" /> property of the result.</param>\r
116         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>\r
117         public ListInitExpression Update(NewExpression newExpression, IEnumerable<ElementInit> initializers) {\r
118             if (newExpression == NewExpression && initializers == Initializers) {\r
119                 return this;\r
120             }\r
121             return Expression.ListInit(newExpression, initializers);\r
122         }\r
123     }\r
124 \r
125 \r
126     public partial class Expression {\r
127         /// <summary>\r
128         /// Creates a <see cref="ListInitExpression"/> that uses a method named "Add" to add elements to a collection.\r
129         /// </summary>\r
130         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>\r
131         /// <param name="initializers">An array of <see cref="Expression"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>\r
132         /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>\r
133         public static ListInitExpression ListInit(NewExpression newExpression, params Expression[] initializers) {\r
134             ContractUtils.RequiresNotNull(newExpression, "newExpression");\r
135             ContractUtils.RequiresNotNull(initializers, "initializers");\r
136             return ListInit(newExpression, initializers as IEnumerable<Expression>);\r
137         }\r
138 \r
139         /// <summary>\r
140         /// Creates a <see cref="ListInitExpression"/> that uses a method named "Add" to add elements to a collection.\r
141         /// </summary>\r
142         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>\r
143         /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>\r
144         /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>\r
145         public static ListInitExpression ListInit(NewExpression newExpression, IEnumerable<Expression> initializers) {\r
146             ContractUtils.RequiresNotNull(newExpression, "newExpression");\r
147             ContractUtils.RequiresNotNull(initializers, "initializers");\r
148 \r
149             var initializerlist = initializers.ToReadOnly();\r
150             if (initializerlist.Count == 0) {\r
151                 throw Error.ListInitializerWithZeroMembers();\r
152             }\r
153 \r
154             MethodInfo addMethod = FindMethod(newExpression.Type, "Add", null, new Expression[] { initializerlist[0] }, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
155             return ListInit(newExpression, addMethod, initializers);\r
156         }\r
157 \r
158         /// <summary>\r
159         /// Creates a <see cref="ListInitExpression"/> that uses a specified method to add elements to a collection. \r
160         /// </summary>\r
161         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>\r
162         /// <param name="addMethod">A <see cref="MethodInfo"/> that represents an instance method named "Add" (case insensitive), that adds an element to a collection. </param>\r
163         /// <param name="initializers">An array of <see cref="Expression"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>\r
164         /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>\r
165         public static ListInitExpression ListInit(NewExpression newExpression, MethodInfo addMethod, params Expression[] initializers) {\r
166             if (addMethod == null) {\r
167                 return ListInit(newExpression, initializers as IEnumerable<Expression>);\r
168             }\r
169             ContractUtils.RequiresNotNull(newExpression, "newExpression");\r
170             ContractUtils.RequiresNotNull(initializers, "initializers");\r
171             return ListInit(newExpression, addMethod, initializers as IEnumerable<Expression>);\r
172         }\r
173 \r
174         /// <summary>\r
175         /// Creates a <see cref="ListInitExpression"/> that uses a specified method to add elements to a collection. \r
176         /// </summary>\r
177         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>\r
178         /// <param name="addMethod">A <see cref="MethodInfo"/> that represents an instance method named "Add" (case insensitive), that adds an element to a collection. </param>\r
179         /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="Expression"/> objects to use to populate the Initializers collection.</param>\r
180         /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>\r
181         public static ListInitExpression ListInit(NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers) {\r
182             if (addMethod == null) {\r
183                 return ListInit(newExpression, initializers);\r
184             }\r
185             ContractUtils.RequiresNotNull(newExpression, "newExpression");\r
186             ContractUtils.RequiresNotNull(initializers, "initializers");\r
187 \r
188             var initializerlist = initializers.ToReadOnly();\r
189             if (initializerlist.Count == 0) {\r
190                 throw Error.ListInitializerWithZeroMembers();\r
191             }\r
192             ElementInit[] initList = new ElementInit[initializerlist.Count];\r
193             for (int i = 0; i < initializerlist.Count; i++) {\r
194                 initList[i] = ElementInit(addMethod, initializerlist[i]);\r
195             }\r
196             return ListInit(newExpression, new TrueReadOnlyCollection<ElementInit>(initList));\r
197         }\r
198 \r
199         /// <summary>\r
200         /// Creates a <see cref="ListInitExpression"/> that uses specified <see cref="M:ElementInit"/> objects to initialize a collection. \r
201         /// </summary>\r
202         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>\r
203         /// <param name="initializers">An array that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>\r
204         /// <returns>\r
205         /// A <see cref="ListInitExpression"/> that has the <see cref="P:Expressions.NodeType"/> property equal to ListInit \r
206         /// and the <see cref="P:ListInitExpression.NewExpression"/> and <see cref="P:ListInitExpression.Initializers"/> properties set to the specified values.\r
207         /// </returns>\r
208         /// <remarks>\r
209         /// The <see cref="P:Expressions.Type"/> property of <paramref name="newExpression"/> must represent a type that implements <see cref="System.Collections.IEnumerable"/>. \r
210         /// The <see cref="P:Expressions.Type"/> property of the resulting <see cref="ListInitExpression"/> is equal to newExpression.Type. \r
211         /// </remarks>\r
212         public static ListInitExpression ListInit(NewExpression newExpression, params ElementInit[] initializers) {\r
213             return ListInit(newExpression, (IEnumerable<ElementInit>)initializers);\r
214         }\r
215 \r
216         /// <summary>\r
217         /// Creates a <see cref="ListInitExpression"/> that uses specified <see cref="M:ElementInit"/> objects to initialize a collection. \r
218         /// </summary>\r
219         /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>\r
220         /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>\r
221         /// <returns>An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</returns>\r
222         /// <remarks>\r
223         /// The <see cref="P:Expressions.Type"/> property of <paramref name="newExpression"/> must represent a type that implements <see cref="System.Collections.IEnumerable"/>. \r
224         /// The <see cref="P:Expressions.Type"/> property of the resulting <see cref="ListInitExpression"/> is equal to newExpression.Type. \r
225         /// </remarks>\r
226         public static ListInitExpression ListInit(NewExpression newExpression, IEnumerable<ElementInit> initializers) {\r
227             ContractUtils.RequiresNotNull(newExpression, "newExpression");\r
228             ContractUtils.RequiresNotNull(initializers, "initializers");\r
229             var initializerlist = initializers.ToReadOnly();\r
230             if (initializerlist.Count == 0) {\r
231                 throw Error.ListInitializerWithZeroMembers();\r
232             }\r
233             ValidateListInitArgs(newExpression.Type, initializerlist);\r
234             return new ListInitExpression(newExpression, initializerlist);\r
235         }\r
236     }\r
237 }\r