1 /* ****************************************************************************
\r
3 * Copyright (c) Microsoft Corporation.
\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
11 * You must not remove this notice, or any other, from this software.
\r
14 * ***************************************************************************/
\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
29 namespace Microsoft.Scripting.Ast {
\r
31 namespace System.Linq.Expressions {
\r
34 /// Represents a constructor call that has a collection initializer.
\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
41 [DebuggerTypeProxy(typeof(Expression.ListInitExpressionProxy))]
\r
43 public sealed class ListInitExpression : Expression {
\r
44 private readonly NewExpression _newExpression;
\r
45 private readonly ReadOnlyCollection<ElementInit> _initializers;
\r
47 internal ListInitExpression(NewExpression newExpression, ReadOnlyCollection<ElementInit> initializers) {
\r
48 _newExpression = newExpression;
\r
49 _initializers = initializers;
\r
53 /// Returns the node type of this <see cref="Expression"/>. (Inherited from <see cref="Expression" />.)
\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
61 /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
\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
69 /// Gets a value that indicates whether the expression tree node can be reduced.
\r
71 public override bool CanReduce {
\r
78 /// Gets the expression that contains a call to the constructor of a collection type.
\r
80 public NewExpression NewExpression {
\r
81 get { return _newExpression; }
\r
85 /// Gets the element initializers that are used to initialize a collection.
\r
87 public ReadOnlyCollection<ElementInit> Initializers {
\r
88 get { return _initializers; }
\r
92 /// Dispatches to the specific visit method for this node type.
\r
94 protected internal override Expression Accept(ExpressionVisitor visitor) {
\r
95 return visitor.VisitListInit(this);
\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
104 /// <returns>The reduced expression.</returns>
\r
105 public override Expression Reduce() {
\r
106 return MemberInitExpression.ReduceListInit(_newExpression, _initializers, true);
\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
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
121 return Expression.ListInit(newExpression, initializers);
\r
126 public partial class Expression {
\r
128 /// Creates a <see cref="ListInitExpression"/> that uses a method named "Add" to add elements to a collection.
\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
140 /// Creates a <see cref="ListInitExpression"/> that uses a method named "Add" to add elements to a collection.
\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
149 var initializerlist = initializers.ToReadOnly();
\r
150 if (initializerlist.Count == 0) {
\r
151 throw Error.ListInitializerWithZeroMembers();
\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
159 /// Creates a <see cref="ListInitExpression"/> that uses a specified method to add elements to a collection.
\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
169 ContractUtils.RequiresNotNull(newExpression, "newExpression");
\r
170 ContractUtils.RequiresNotNull(initializers, "initializers");
\r
171 return ListInit(newExpression, addMethod, initializers as IEnumerable<Expression>);
\r
175 /// Creates a <see cref="ListInitExpression"/> that uses a specified method to add elements to a collection.
\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
185 ContractUtils.RequiresNotNull(newExpression, "newExpression");
\r
186 ContractUtils.RequiresNotNull(initializers, "initializers");
\r
188 var initializerlist = initializers.ToReadOnly();
\r
189 if (initializerlist.Count == 0) {
\r
190 throw Error.ListInitializerWithZeroMembers();
\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
196 return ListInit(newExpression, new TrueReadOnlyCollection<ElementInit>(initList));
\r
200 /// Creates a <see cref="ListInitExpression"/> that uses specified <see cref="M:ElementInit"/> objects to initialize a collection.
\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
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
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
212 public static ListInitExpression ListInit(NewExpression newExpression, params ElementInit[] initializers) {
\r
213 return ListInit(newExpression, (IEnumerable<ElementInit>)initializers);
\r
217 /// Creates a <see cref="ListInitExpression"/> that uses specified <see cref="M:ElementInit"/> objects to initialize a collection.
\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
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
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
233 ValidateListInitArgs(newExpression.Type, initializerlist);
\r
234 return new ListInitExpression(newExpression, initializerlist);
\r