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 * ***************************************************************************/
15 using System; using Microsoft;
18 using System.Collections.Generic;
19 using System.Collections.ObjectModel;
20 using System.Diagnostics;
22 using System.Dynamic.Utils;
24 using Microsoft.Scripting.Utils;
26 using System.Runtime.CompilerServices;
28 using Microsoft.Runtime.CompilerServices;
33 namespace System.Linq.Expressions {
35 namespace Microsoft.Linq.Expressions {
38 /// Represents calling a constructor and initializing one or more members of the new object.
41 [DebuggerTypeProxy(typeof(Expression.MemberInitExpressionProxy))]
43 public sealed class MemberInitExpression : Expression {
44 private readonly NewExpression _newExpression;
45 private readonly ReadOnlyCollection<MemberBinding> _bindings;
47 internal MemberInitExpression(NewExpression newExpression, ReadOnlyCollection<MemberBinding> bindings) {
48 _newExpression = newExpression;
53 /// Gets the static type of the expression that this <see cref="Expression" /> represents.
55 /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
56 public sealed override Type Type {
57 get { return _newExpression.Type; }
61 /// Gets a value that indicates whether the expression tree node can be reduced.
63 public override bool CanReduce {
70 /// Returns the node type of this Expression. Extension nodes should return
71 /// ExpressionType.Extension when overriding this method.
73 /// <returns>The <see cref="ExpressionType"/> of the expression.</returns>
74 public sealed override ExpressionType NodeType {
75 get { return ExpressionType.MemberInit; }
78 ///<summary>Gets the expression that represents the constructor call.</summary>
79 ///<returns>A <see cref="T:Microsoft.Linq.Expressions.NewExpression" /> that represents the constructor call.</returns>
80 public NewExpression NewExpression {
81 get { return _newExpression; }
84 ///<summary>Gets the bindings that describe how to initialize the members of the newly created object.</summary>
85 ///<returns>A <see cref="T:System.Collections.ObjectModel.ReadOnlyCollection`1" /> of <see cref="T:Microsoft.Linq.Expressions.MemberBinding" /> objects which describe how to initialize the members.</returns>
86 public ReadOnlyCollection<MemberBinding> Bindings {
87 get { return _bindings; }
90 internal override Expression Accept(ExpressionVisitor visitor) {
91 return visitor.VisitMemberInit(this);
95 /// Reduces the <see cref="MemberInitExpression"/> to a simpler expression.
96 /// If CanReduce returns true, this should return a valid expression.
97 /// This method is allowed to return another node which itself
100 /// <returns>The reduced expression.</returns>
101 public override Expression Reduce() {
102 return ReduceMemberInit(_newExpression, _bindings, true);
105 internal static Expression ReduceMemberInit(Expression objExpression, ReadOnlyCollection<MemberBinding> bindings, bool keepOnStack) {
106 var objVar = Expression.Variable(objExpression.Type, null);
107 int count = bindings.Count;
108 var block = new Expression[count + 2];
109 block[0] = Expression.Assign(objVar, objExpression);
110 for (int i = 0; i < count; i++) {
111 block[i + 1] = ReduceMemberBinding(objVar, bindings[i]);
113 block[count + 1] = keepOnStack ? (Expression)objVar : Expression.Empty();
114 return Expression.Block(new TrueReadOnlyCollection<Expression>(block));
117 internal static Expression ReduceListInit(Expression listExpression, ReadOnlyCollection<ElementInit> initializers, bool keepOnStack) {
118 var listVar = Expression.Variable(listExpression.Type, null);
119 int count = initializers.Count;
120 var block = new Expression[count + 2];
121 block[0] = Expression.Assign(listVar, listExpression);
122 for (int i = 0; i < count; i++) {
123 ElementInit element = initializers[i];
124 block[i + 1] = Expression.Call(listVar, element.AddMethod, element.Arguments);
126 block[count + 1] = keepOnStack ? (Expression)listVar : Expression.Empty();
127 return Expression.Block(new TrueReadOnlyCollection<Expression>(block));
130 internal static Expression ReduceMemberBinding(ParameterExpression objVar, MemberBinding binding) {
131 MemberExpression member = Expression.MakeMemberAccess(objVar, binding.Member);
132 switch (binding.BindingType) {
133 case MemberBindingType.Assignment:
134 return Expression.Assign(member, ((MemberAssignment)binding).Expression);
135 case MemberBindingType.ListBinding:
136 return ReduceListInit(member, ((MemberListBinding)binding).Initializers, false);
137 case MemberBindingType.MemberBinding:
138 return ReduceMemberInit(member, ((MemberMemberBinding)binding).Bindings, false);
139 default: throw ContractUtils.Unreachable;
144 public partial class Expression {
145 ///<summary>Creates a <see cref="T:Microsoft.Linq.Expressions.MemberInitExpression" />.</summary>
146 ///<returns>A <see cref="T:Microsoft.Linq.Expressions.MemberInitExpression" /> that has the <see cref="P:Microsoft.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:Microsoft.Linq.Expressions.ExpressionType.MemberInit" /> and the <see cref="P:Microsoft.Linq.Expressions.MemberInitExpression.NewExpression" /> and <see cref="P:Microsoft.Linq.Expressions.MemberInitExpression.Bindings" /> properties set to the specified values.</returns>
147 ///<param name="newExpression">A <see cref="T:Microsoft.Linq.Expressions.NewExpression" /> to set the <see cref="P:Microsoft.Linq.Expressions.MemberInitExpression.NewExpression" /> property equal to.</param>
148 ///<param name="bindings">An array of <see cref="T:Microsoft.Linq.Expressions.MemberBinding" /> objects to use to populate the <see cref="P:Microsoft.Linq.Expressions.MemberInitExpression.Bindings" /> collection.</param>
149 ///<exception cref="T:System.ArgumentNullException">
150 ///<paramref name="newExpression" /> or <paramref name="bindings" /> is null.</exception>
151 ///<exception cref="T:System.ArgumentException">The <see cref="P:Microsoft.Linq.Expressions.MemberBinding.Member" /> property of an element of <paramref name="bindings" /> does not represent a member of the type that <paramref name="newExpression" />.Type represents.</exception>
152 public static MemberInitExpression MemberInit(NewExpression newExpression, params MemberBinding[] bindings) {
153 return MemberInit(newExpression, (IEnumerable<MemberBinding>)bindings);
156 ///<summary>Creates a <see cref="T:Microsoft.Linq.Expressions.MemberInitExpression" />.</summary>
157 ///<returns>A <see cref="T:Microsoft.Linq.Expressions.MemberInitExpression" /> that has the <see cref="P:Microsoft.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:Microsoft.Linq.Expressions.ExpressionType.MemberInit" /> and the <see cref="P:Microsoft.Linq.Expressions.MemberInitExpression.NewExpression" /> and <see cref="P:Microsoft.Linq.Expressions.MemberInitExpression.Bindings" /> properties set to the specified values.</returns>
158 ///<param name="newExpression">A <see cref="T:Microsoft.Linq.Expressions.NewExpression" /> to set the <see cref="P:Microsoft.Linq.Expressions.MemberInitExpression.NewExpression" /> property equal to.</param>
159 ///<param name="bindings">An <see cref="T:System.Collections.Generic.IEnumerable`1" /> that contains <see cref="T:Microsoft.Linq.Expressions.MemberBinding" /> objects to use to populate the <see cref="P:Microsoft.Linq.Expressions.MemberInitExpression.Bindings" /> collection.</param>
160 ///<exception cref="T:System.ArgumentNullException">
161 ///<paramref name="newExpression" /> or <paramref name="bindings" /> is null.</exception>
162 ///<exception cref="T:System.ArgumentException">The <see cref="P:Microsoft.Linq.Expressions.MemberBinding.Member" /> property of an element of <paramref name="bindings" /> does not represent a member of the type that <paramref name="newExpression" />.Type represents.</exception>
163 public static MemberInitExpression MemberInit(NewExpression newExpression, IEnumerable<MemberBinding> bindings) {
164 ContractUtils.RequiresNotNull(newExpression, "newExpression");
165 ContractUtils.RequiresNotNull(bindings, "bindings");
166 var roBindings = bindings.ToReadOnly();
167 ValidateMemberInitArgs(newExpression.Type, roBindings);
168 return new MemberInitExpression(newExpression, roBindings);