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;
29 namespace Microsoft.Scripting.Ast {
31 namespace System.Linq.Expressions {
35 /// Represents a constructor call.
38 [DebuggerTypeProxy(typeof(Expression.NewExpressionProxy))]
40 public class NewExpression : Expression, IArgumentProvider {
41 private readonly ConstructorInfo _constructor;
42 private IList<Expression> _arguments;
43 private readonly ReadOnlyCollection<MemberInfo> _members;
45 internal NewExpression(ConstructorInfo constructor, IList<Expression> arguments, ReadOnlyCollection<MemberInfo> members) {
46 _constructor = constructor;
47 _arguments = arguments;
52 /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
54 /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
55 public override Type Type {
56 get { return _constructor.DeclaringType; }
60 /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
62 /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
63 public sealed override ExpressionType NodeType {
64 get { return ExpressionType.New; }
68 /// Gets the called constructor.
70 public ConstructorInfo Constructor {
71 get { return _constructor; }
75 /// Gets the arguments to the constructor.
77 public ReadOnlyCollection<Expression> Arguments {
78 get { return ReturnReadOnly(ref _arguments); }
81 Expression IArgumentProvider.GetArgument(int index) {
82 return _arguments[index];
85 int IArgumentProvider.ArgumentCount {
87 return _arguments.Count;
92 /// Gets the members that can retrieve the values of the fields that were initialized with constructor arguments.
94 public ReadOnlyCollection<MemberInfo> Members {
95 get { return _members; }
99 /// Dispatches to the specific visit method for this node type.
101 protected internal override Expression Accept(ExpressionVisitor visitor) {
102 return visitor.VisitNew(this);
106 /// Creates a new expression that is like this one, but using the
107 /// supplied children. If all of the children are the same, it will
108 /// return this expression.
110 /// <param name="arguments">The <see cref="Arguments" /> property of the result.</param>
111 /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
112 public NewExpression Update(IEnumerable<Expression> arguments) {
113 if (arguments == Arguments) {
116 if (Members != null) {
117 return Expression.New(Constructor, arguments, Members);
119 return Expression.New(Constructor, arguments);
123 internal class NewValueTypeExpression : NewExpression {
124 private readonly Type _valueType;
126 internal NewValueTypeExpression(Type type, ReadOnlyCollection<Expression> arguments, ReadOnlyCollection<MemberInfo> members)
127 : base(null, arguments, members) {
131 public sealed override Type Type {
132 get { return _valueType; }
136 public partial class Expression {
139 /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor that takes no arguments.
141 /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
142 /// <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>
143 public static NewExpression New(ConstructorInfo constructor) {
144 return New(constructor, (IEnumerable<Expression>)null);
149 /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor that takes no arguments.
151 /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
152 /// <param name="arguments">An array of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
153 /// <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>
154 public static NewExpression New(ConstructorInfo constructor, params Expression[] arguments) {
155 return New(constructor, (IEnumerable<Expression>)arguments);
160 /// Creates a new <see cref="NewExpression"/> that represents calling the specified constructor that takes no arguments.
162 /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
163 /// <param name="arguments">An <see cref="IEnumerable{T}"/> of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
164 /// <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>
165 public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments) {
166 ContractUtils.RequiresNotNull(constructor, "constructor");
167 ContractUtils.RequiresNotNull(constructor.DeclaringType, "constructor.DeclaringType");
168 TypeUtils.ValidateType(constructor.DeclaringType);
169 var argList = arguments.ToReadOnly();
170 ValidateArgumentTypes(constructor, ExpressionType.New, ref argList);
172 return new NewExpression(constructor, argList, null);
177 /// 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.
179 /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
180 /// <param name="arguments">An <see cref="IEnumerable{T}"/> of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
181 /// <param name="members">An <see cref="IEnumerable{T}"/> of <see cref="MemberInfo"/> objects to use to populate the Members collection.</param>
182 /// <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>
183 public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members) {
184 ContractUtils.RequiresNotNull(constructor, "constructor");
185 var memberList = members.ToReadOnly();
186 var argList = arguments.ToReadOnly();
187 ValidateNewArgs(constructor, ref argList, ref memberList);
188 return new NewExpression(constructor, argList, memberList);
193 /// 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.
195 /// <param name="constructor">The <see cref="ConstructorInfo"/> to set the <see cref="P:Constructor"/> property equal to.</param>
196 /// <param name="arguments">An <see cref="IEnumerable{T}"/> of <see cref="Expression"/> objects to use to populate the Arguments collection.</param>
197 /// <param name="members">An Array of <see cref="MemberInfo"/> objects to use to populate the Members collection.</param>
198 /// <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>
199 public static NewExpression New(ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo[] members) {
200 return New(constructor, arguments, (IEnumerable<MemberInfo>)members);
205 /// Creates a <see cref="NewExpression"/> that represents calling the parameterless constructor of the specified type.
207 /// <param name="type">A <see cref="Type"/> that has a constructor that takes no arguments. </param>
208 /// <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>
209 public static NewExpression New(Type type) {
210 ContractUtils.RequiresNotNull(type, "type");
211 if (type == typeof(void)) {
212 throw Error.ArgumentCannotBeOfTypeVoid();
214 ConstructorInfo ci = null;
215 if (!type.IsValueType) {
216 ci = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, System.Type.EmptyTypes, null);
218 throw Error.TypeMissingDefaultConstructor(type);
222 return new NewValueTypeExpression(type, EmptyReadOnlyCollection<Expression>.Instance, null);
227 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
228 private static void ValidateNewArgs(ConstructorInfo constructor, ref ReadOnlyCollection<Expression> arguments, ref ReadOnlyCollection<MemberInfo> members) {
230 if ((pis = constructor.GetParametersCached()).Length > 0) {
231 if (arguments.Count != pis.Length) {
232 throw Error.IncorrectNumberOfConstructorArguments();
234 if (arguments.Count != members.Count) {
235 throw Error.IncorrectNumberOfArgumentsForMembers();
237 Expression[] newArguments = null;
238 MemberInfo[] newMembers = null;
239 for (int i = 0, n = arguments.Count; i < n; i++) {
240 Expression arg = arguments[i];
241 RequiresCanRead(arg, "argument");
242 MemberInfo member = members[i];
243 ContractUtils.RequiresNotNull(member, "member");
244 if (!TypeUtils.AreEquivalent(member.DeclaringType, constructor.DeclaringType)) {
245 throw Error.ArgumentMemberNotDeclOnType(member.Name, constructor.DeclaringType.Name);
248 ValidateAnonymousTypeMember(ref member, out memberType);
249 if (!TypeUtils.AreReferenceAssignable(memberType, arg.Type)) {
250 if (!TryQuote(memberType, ref arg)) {
251 throw Error.ArgumentTypeDoesNotMatchMember(arg.Type, memberType);
254 ParameterInfo pi = pis[i];
255 Type pType = pi.ParameterType;
257 pType = pType.GetElementType();
259 if (!TypeUtils.AreReferenceAssignable(pType, arg.Type)) {
260 if (!TryQuote(pType, ref arg)) {
261 throw Error.ExpressionTypeDoesNotMatchConstructorParameter(arg.Type, pType);
264 if (newArguments == null && arg != arguments[i]) {
265 newArguments = new Expression[arguments.Count];
266 for (int j = 0; j < i; j++) {
267 newArguments[j] = arguments[j];
270 if (newArguments != null) {
271 newArguments[i] = arg;
274 if (newMembers == null && member != members[i]) {
275 newMembers = new MemberInfo[members.Count];
276 for (int j = 0; j < i; j++) {
277 newMembers[j] = members[j];
280 if (newMembers != null) {
281 newMembers[i] = member;
284 if (newArguments != null) {
285 arguments = new TrueReadOnlyCollection<Expression>(newArguments);
287 if (newMembers != null) {
288 members = new TrueReadOnlyCollection<MemberInfo>(newMembers);
290 } else if (arguments != null && arguments.Count > 0) {
291 throw Error.IncorrectNumberOfConstructorArguments();
292 } else if (members != null && members.Count > 0) {
293 throw Error.IncorrectNumberOfMembersForGivenConstructor();
298 private static void ValidateAnonymousTypeMember(ref MemberInfo member, out Type memberType) {
299 switch (member.MemberType) {
300 case MemberTypes.Field:
301 FieldInfo field = member as FieldInfo;
302 if (field.IsStatic) {
303 throw Error.ArgumentMustBeInstanceMember();
305 memberType = field.FieldType;
307 case MemberTypes.Property:
308 PropertyInfo pi = member as PropertyInfo;
310 throw Error.PropertyDoesNotHaveGetter(pi);
312 if (pi.GetGetMethod().IsStatic) {
313 throw Error.ArgumentMustBeInstanceMember();
315 memberType = pi.PropertyType;
317 case MemberTypes.Method:
318 MethodInfo method = member as MethodInfo;
319 if (method.IsStatic) {
320 throw Error.ArgumentMustBeInstanceMember();
323 if (SilverlightQuirks) {
324 // we used to just store the MethodInfo
325 memberType = method.ReturnType;
329 PropertyInfo prop = GetProperty(method);
331 memberType = prop.PropertyType;
334 throw Error.ArgumentMustBeFieldInfoOrPropertInfoOrMethod();
336 // don't add code here, we've already returned