1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
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.Diagnostics;
20 using System.Dynamic.Utils;
21 using System.Reflection;
22 using System.Runtime.CompilerServices;
23 //using Microsoft.Scripting.Utils;
26 namespace Microsoft.Scripting.Ast {
28 namespace System.Linq.Expressions {
31 /// Represents a constructor call.
33 [DebuggerTypeProxy(typeof(Expression.NewExpressionProxy))]
34 public class NewExpression : Expression, IArgumentProvider {
35 private readonly ConstructorInfo _constructor;
36 private IList<Expression> _arguments;
37 private readonly ReadOnlyCollection<MemberInfo> _members;
39 internal NewExpression(ConstructorInfo constructor, IList<Expression> arguments, ReadOnlyCollection<MemberInfo> members) {
40 _constructor = constructor;
41 _arguments = arguments;
46 /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
48 /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
49 public override Type Type {
50 get { return _constructor.DeclaringType; }
54 /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
56 /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
57 public sealed override ExpressionType NodeType {
58 get { return ExpressionType.New; }
62 /// Gets the called constructor.
64 public ConstructorInfo Constructor {
65 get { return _constructor; }
69 /// Gets the arguments to the constructor.
71 public ReadOnlyCollection<Expression> Arguments {
72 get { return ReturnReadOnly(ref _arguments); }
75 Expression IArgumentProvider.GetArgument(int index) {
76 return _arguments[index];
79 int IArgumentProvider.ArgumentCount {
81 return _arguments.Count;
86 /// Gets the members that can retrieve the values of the fields that were initialized with constructor arguments.
88 public ReadOnlyCollection<MemberInfo> Members {
89 get { return _members; }
93 /// Dispatches to the specific visit method for this node type.
95 protected internal override Expression Accept(ExpressionVisitor visitor) {
96 return visitor.VisitNew(this);
100 /// Creates a new expression that is like this one, but using the
101 /// supplied children. If all of the children are the same, it will
102 /// return this expression.
104 /// <param name="arguments">The <see cref="Arguments" /> property of the result.</param>
105 /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
106 public NewExpression Update(IEnumerable<Expression> arguments) {
107 if (arguments == Arguments) {
110 if (Members != null) {
111 return Expression.New(Constructor, arguments, Members);
113 return Expression.New(Constructor, arguments);
117 internal class NewValueTypeExpression : NewExpression {
118 private readonly Type _valueType;
120 internal NewValueTypeExpression(Type type, ReadOnlyCollection<Expression> arguments, ReadOnlyCollection<MemberInfo> members)
121 : base(null, arguments, members) {
125 public sealed override Type Type {
126 get { return _valueType; }
130 public partial class Expression {
133 /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor that takes no arguments.
135 /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
136 /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="P:New"/> and the <see cref="P:Constructor"/> property set to the specified value.</returns>
137 public static NewExpression New(ConstructorInfo constructor) {
138 return New(constructor, (IEnumerable<Expression>)null);
143 /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor that takes no arguments.
145 /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
146 /// <param name="arguments">An array of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
147 /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="P:New"/> and the <see cref="P:Constructor"/> and <see cref="P:Arguments"/> properties set to the specified value.</returns>
148 public static NewExpression New(ConstructorInfo constructor, params Expression[] arguments) {
149 return New(constructor, (IEnumerable<Expression>)arguments);
154 /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor that takes no arguments.
156 /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
157 /// <param name="arguments">An <see cref="IEnumerable{T}"/> of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
158 /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="P:New"/> and the <see cref="P:Constructor"/> and <see cref="P:Arguments"/> properties set to the specified value.</returns>
159 public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments) {
160 ContractUtils.RequiresNotNull(constructor, "constructor");
161 ContractUtils.RequiresNotNull(constructor.DeclaringType, "constructor.DeclaringType");
162 TypeUtils.ValidateType(constructor.DeclaringType);
163 var argList = arguments.ToReadOnly();
164 ValidateArgumentTypes(constructor, ExpressionType.New, ref argList);
166 return new NewExpression(constructor, argList, null);
171 /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor with the specified arguments. The members that access the constructor initialized fields are specified.
173 /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
174 /// <param name="arguments">An <see cref="IEnumerable{T}"/> of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
175 /// <param name="members">An <see cref="IEnumerable{T}"/> of <see cref="MemberInfo"/> objects to use to populate the Members collection.</param>
176 /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="P:New"/> and the <see cref="P:Constructor"/>, <see cref="P:Arguments"/> and <see cref="P:Members"/> properties set to the specified value.</returns>
177 public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members) {
178 ContractUtils.RequiresNotNull(constructor, "constructor");
179 var memberList = members.ToReadOnly();
180 var argList = arguments.ToReadOnly();
181 ValidateNewArgs(constructor, ref argList, ref memberList);
182 return new NewExpression(constructor, argList, memberList);
187 /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor with the specified arguments. The members that access the constructor initialized fields are specified.
189 /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
190 /// <param name="arguments">An <see cref="IEnumerable{T}"/> of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
191 /// <param name="members">An Array of <see cref="MemberInfo"/> objects to use to populate the Members collection.</param>
192 /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="P:New"/> and the <see cref="P:Constructor"/>, <see cref="P:Arguments"/> and <see cref="P:Members"/> properties set to the specified value.</returns>
193 public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo[] members) {
194 return New(constructor, arguments, (IEnumerable<MemberInfo>)members);
199 /// Creates a <see cref="NewExpression"/> that represents calling the parameterless constructor of the specified type.
201 /// <param name="type">A <see cref="Type"/> that has a constructor that takes no arguments. </param>
202 /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to New and the Constructor property set to the ConstructorInfo that represents the parameterless constructor of the specified type.</returns>
203 public static NewExpression New(Type type) {
204 ContractUtils.RequiresNotNull(type, "type");
205 if (type == typeof(void)) {
206 throw Error.ArgumentCannotBeOfTypeVoid();
208 ConstructorInfo ci = null;
209 if (!type.IsValueType) {
210 ci = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Microsoft.Scripting.Utils.ReflectionUtils.EmptyTypes, null);
212 throw Error.TypeMissingDefaultConstructor(type);
216 return new NewValueTypeExpression(type, EmptyReadOnlyCollection<Expression>.Instance, null);
221 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
222 private static void ValidateNewArgs(ConstructorInfo constructor, ref ReadOnlyCollection<Expression> arguments, ref ReadOnlyCollection<MemberInfo> members) {
224 if ((pis = constructor.GetParametersCached()).Length > 0) {
225 if (arguments.Count != pis.Length) {
226 throw Error.IncorrectNumberOfConstructorArguments();
228 if (arguments.Count != members.Count) {
229 throw Error.IncorrectNumberOfArgumentsForMembers();
231 Expression[] newArguments = null;
232 MemberInfo[] newMembers = null;
233 for (int i = 0, n = arguments.Count; i < n; i++) {
234 Expression arg = arguments[i];
235 RequiresCanRead(arg, "argument");
236 MemberInfo member = members[i];
237 ContractUtils.RequiresNotNull(member, "member");
238 if (!TypeUtils.AreEquivalent(member.DeclaringType, constructor.DeclaringType)) {
239 throw Error.ArgumentMemberNotDeclOnType(member.Name, constructor.DeclaringType.Name);
242 ValidateAnonymousTypeMember(ref member, out memberType);
243 if (!TypeUtils.AreReferenceAssignable(memberType, arg.Type)) {
244 if (!TryQuote(memberType, ref arg)) {
245 throw Error.ArgumentTypeDoesNotMatchMember(arg.Type, memberType);
248 ParameterInfo pi = pis[i];
249 Type pType = pi.ParameterType;
251 pType = pType.GetElementType();
253 if (!TypeUtils.AreReferenceAssignable(pType, arg.Type)) {
254 if (!TryQuote(pType, ref arg)) {
255 throw Error.ExpressionTypeDoesNotMatchConstructorParameter(arg.Type, pType);
258 if (newArguments == null && arg != arguments[i]) {
259 newArguments = new Expression[arguments.Count];
260 for (int j = 0; j < i; j++) {
261 newArguments[j] = arguments[j];
264 if (newArguments != null) {
265 newArguments[i] = arg;
268 if (newMembers == null && member != members[i]) {
269 newMembers = new MemberInfo[members.Count];
270 for (int j = 0; j < i; j++) {
271 newMembers[j] = members[j];
274 if (newMembers != null) {
275 newMembers[i] = member;
278 if (newArguments != null) {
279 arguments = new TrueReadOnlyCollection<Expression>(newArguments);
281 if (newMembers != null) {
282 members = new TrueReadOnlyCollection<MemberInfo>(newMembers);
284 } else if (arguments != null && arguments.Count > 0) {
285 throw Error.IncorrectNumberOfConstructorArguments();
286 } else if (members != null && members.Count > 0) {
287 throw Error.IncorrectNumberOfMembersForGivenConstructor();
292 private static void ValidateAnonymousTypeMember(ref MemberInfo member, out Type memberType) {
293 switch (member.MemberType) {
294 case MemberTypes.Field:
295 FieldInfo field = member as FieldInfo;
296 if (field.IsStatic) {
297 throw Error.ArgumentMustBeInstanceMember();
299 memberType = field.FieldType;
301 case MemberTypes.Property:
302 PropertyInfo pi = member as PropertyInfo;
304 throw Error.PropertyDoesNotHaveGetter(pi);
306 if (pi.GetGetMethod().IsStatic) {
307 throw Error.ArgumentMustBeInstanceMember();
309 memberType = pi.PropertyType;
311 case MemberTypes.Method:
312 MethodInfo method = member as MethodInfo;
313 if (method.IsStatic) {
314 throw Error.ArgumentMustBeInstanceMember();
316 PropertyInfo prop = GetProperty(method);
318 memberType = prop.PropertyType;
321 throw Error.ArgumentMustBeFieldInfoOrPropertInfoOrMethod();
323 // don't add code here, we've already returned