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 * ***************************************************************************/
17 using System.Collections.Generic;
18 using System.Collections.ObjectModel;
19 using System.Reflection;
21 using System.Dynamic.Utils;
28 namespace Microsoft.Scripting.Ast {
30 namespace System.Linq.Expressions {
33 /// Represents the initialization of a list.
35 public sealed class ElementInit : IArgumentProvider {
36 private MethodInfo _addMethod;
37 private ReadOnlyCollection<Expression> _arguments;
39 internal ElementInit(MethodInfo addMethod, ReadOnlyCollection<Expression> arguments) {
40 _addMethod = addMethod;
41 _arguments = arguments;
44 /// Gets the <see cref="MethodInfo"/> used to add elements to the object.
46 public MethodInfo AddMethod {
47 get { return _addMethod; }
51 /// Gets the list of elements to be added to the object.
53 public ReadOnlyCollection<Expression> Arguments {
54 get { return _arguments; }
57 Expression IArgumentProvider.GetArgument(int index) {
58 return _arguments[index];
61 int IArgumentProvider.ArgumentCount {
63 return _arguments.Count;
68 /// Creates a <see cref="String"/> representation of the node.
70 /// <returns>A <see cref="String"/> representation of the node.</returns>
71 public override string ToString() {
72 return ExpressionStringBuilder.ElementInitBindingToString(this);
76 /// Creates a new expression that is like this one, but using the
77 /// supplied children. If all of the children are the same, it will
78 /// return this expression.
80 /// <param name="arguments">The <see cref="Arguments" /> property of the result.</param>
81 /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
82 public ElementInit Update(IEnumerable<Expression> arguments) {
83 if (arguments == Arguments) {
86 return Expression.ElementInit(AddMethod, arguments);
91 public partial class Expression {
93 /// Creates an <see cref="T:ElementInit">ElementInit</see> expression that represents the initialization of a list.
95 /// <param name="addMethod">The <see cref="MethodInfo"/> for the list's Add method.</param>
96 /// <param name="arguments">An array containing the Expressions to be used to initialize the list.</param>
97 /// <returns>The created <see cref="T:ElementInit">ElementInit</see> expression.</returns>
98 public static ElementInit ElementInit(MethodInfo addMethod, params Expression[] arguments) {
99 return ElementInit(addMethod, arguments as IEnumerable<Expression>);
103 /// Creates an <see cref="T:ElementInit">ElementInit</see> expression that represents the initialization of a list.
105 /// <param name="addMethod">The <see cref="MethodInfo"/> for the list's Add method.</param>
106 /// <param name="arguments">An <see cref="IEnumerable{T}"/> containing <see cref="Expression"/> elements to initialize the list.</param>
107 /// <returns>The created <see cref="T:ElementInit">ElementInit</see> expression.</returns>
108 public static ElementInit ElementInit(MethodInfo addMethod, IEnumerable<Expression> arguments) {
109 ContractUtils.RequiresNotNull(addMethod, "addMethod");
110 ContractUtils.RequiresNotNull(arguments, "arguments");
112 var argumentsRO = arguments.ToReadOnly();
114 RequiresCanRead(argumentsRO, "arguments");
115 ValidateElementInitAddMethodInfo(addMethod);
116 ValidateArgumentTypes(addMethod, ExpressionType.Call, ref argumentsRO);
117 return new ElementInit(addMethod, argumentsRO);
120 private static void ValidateElementInitAddMethodInfo(MethodInfo addMethod) {
121 ValidateMethodInfo(addMethod);
122 ParameterInfo[] pis = addMethod.GetParametersCached();
123 if (pis.Length == 0) {
124 throw Error.ElementInitializerMethodWithZeroArgs();
126 if (!addMethod.Name.Equals("Add", StringComparison.OrdinalIgnoreCase)) {
127 throw Error.ElementInitializerMethodNotAdd();
129 if (addMethod.IsStatic) {
130 throw Error.ElementInitializerMethodStatic();
132 foreach (ParameterInfo pi in pis) {
133 if (pi.ParameterType.IsByRef) {
134 throw Error.ElementInitializerMethodNoRefOutParam(pi.Name, addMethod.Name);