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;
19 using System.Dynamic.Utils;
21 using Microsoft.Scripting.Utils;
23 using System.Diagnostics;
26 namespace System.Linq.Expressions {
28 namespace Microsoft.Linq.Expressions {
32 /// Represents an expression that has a conditional operator.
35 [DebuggerTypeProxy(typeof(Expression.ConditionalExpressionProxy))]
37 public class ConditionalExpression : Expression {
38 private readonly Expression _test;
39 private readonly Expression _true;
41 internal ConditionalExpression(Expression test, Expression ifTrue) {
46 internal static ConditionalExpression Make(Expression test, Expression ifTrue, Expression ifFalse, Type type) {
47 if (ifTrue.Type != type || ifFalse.Type != type) {
48 return new FullConditionalExpressionWithType(test, ifTrue, ifFalse, type);
49 } if (ifFalse is DefaultExpression && ifFalse.Type == typeof(void)) {
50 return new ConditionalExpression(test, ifTrue);
52 return new FullConditionalExpression(test, ifTrue, ifFalse);
57 /// Returns the node type of this Expression. Extension nodes should return
58 /// ExpressionType.Extension when overriding this method.
60 /// <returns>The <see cref="ExpressionType"/> of the expression.</returns>
61 public sealed override ExpressionType NodeType {
62 get { return ExpressionType.Conditional; }
66 /// Gets the static type of the expression that this <see cref="Expression" /> represents.
68 /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
69 public override Type Type {
70 get { return IfTrue.Type; }
74 /// Gets the test of the conditional operation.
76 public Expression Test {
80 /// Gets the expression to execute if the test evaluates to true.
82 public Expression IfTrue {
86 /// Gets the expression to execute if the test evaluates to false.
88 public Expression IfFalse {
89 get { return GetFalse(); }
92 internal virtual Expression GetFalse() {
93 return Expression.Empty();
96 internal override Expression Accept(ExpressionVisitor visitor) {
97 return visitor.VisitConditional(this);
101 internal class FullConditionalExpression : ConditionalExpression {
102 private readonly Expression _false;
104 internal FullConditionalExpression(Expression test, Expression ifTrue, Expression ifFalse)
105 : base(test, ifTrue) {
109 internal override Expression GetFalse() {
114 internal class FullConditionalExpressionWithType : FullConditionalExpression {
115 private readonly Type _type;
117 internal FullConditionalExpressionWithType(Expression test, Expression ifTrue, Expression ifFalse, Type type)
118 : base(test, ifTrue, ifFalse) {
122 public sealed override Type Type {
123 get { return _type; }
127 public partial class Expression {
130 /// Creates a <see cref="ConditionalExpression"/>.
132 /// <param name="test">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.Test"/> property equal to.</param>
133 /// <param name="ifTrue">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfTrue"/> property equal to.</param>
134 /// <param name="ifFalse">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfFalse"/> property equal to.</param>
135 /// <returns>A <see cref="ConditionalExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to
136 /// <see cref="F:ExpressionType.Conditional"/> and the <see cref="P:ConditionalExpression.Test"/>, <see cref="P:ConditionalExpression.IfTrue"/>,
137 /// and <see cref="P:ConditionalExpression.IfFalse"/> properties set to the specified values.</returns>
138 public static ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse) {
139 RequiresCanRead(test, "test");
140 RequiresCanRead(ifTrue, "ifTrue");
141 RequiresCanRead(ifFalse, "ifFalse");
143 if (test.Type != typeof(bool)) {
144 throw Error.ArgumentMustBeBoolean();
146 if (!TypeUtils.AreEquivalent(ifTrue.Type, ifFalse.Type)) {
147 throw Error.ArgumentTypesMustMatch();
150 return ConditionalExpression.Make(test, ifTrue, ifFalse, ifTrue.Type);
155 /// Creates a <see cref="ConditionalExpression"/>.
157 /// <param name="test">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.Test"/> property equal to.</param>
158 /// <param name="ifTrue">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfTrue"/> property equal to.</param>
159 /// <param name="ifFalse">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfFalse"/> property equal to.</param>
160 /// <param name="type">A <see cref="Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
161 /// <returns>A <see cref="ConditionalExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to
162 /// <see cref="F:ExpressionType.Conditional"/> and the <see cref="P:ConditionalExpression.Test"/>, <see cref="P:ConditionalExpression.IfTrue"/>,
163 /// and <see cref="P:ConditionalExpression.IfFalse"/> properties set to the specified values.</returns>
164 /// <remarks>This method allows explicitly unifying the result type of the conditional expression in cases where the types of <paramref name="ifTrue"/>
165 /// and <paramref name="ifFalse"/> expressions are not equal. Types of both <paramref name="ifTrue"/> and <paramref name="ifFalse"/> must be implicitly
166 /// reference assignable to the result type. The <paramref name="type"/> is allowed to be <see cref="System.Void"/>.</remarks>
167 public static ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse, Type type) {
168 RequiresCanRead(test, "test");
169 RequiresCanRead(ifTrue, "ifTrue");
170 RequiresCanRead(ifFalse, "ifFalse");
171 ContractUtils.RequiresNotNull(type, "type");
173 if (test.Type != typeof(bool)) {
174 throw Error.ArgumentMustBeBoolean();
177 if (type != typeof(void)) {
178 if (!TypeUtils.AreReferenceAssignable(type, ifTrue.Type) ||
179 !TypeUtils.AreReferenceAssignable(type, ifFalse.Type)) {
180 throw Error.ArgumentTypesMustMatch();
184 return ConditionalExpression.Make(test, ifTrue, ifFalse, type);
188 /// Creates a <see cref="ConditionalExpression"/>.
190 /// <param name="test">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.Test"/> property equal to.</param>
191 /// <param name="ifTrue">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfTrue"/> property equal to.</param>
192 /// <returns>A <see cref="ConditionalExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to
193 /// <see cref="F:ExpressionType.Conditional"/> and the <see cref="P:ConditionalExpression.Test"/>, <see cref="P:ConditionalExpression.IfTrue"/>,
194 /// properties set to the specified values. The <see cref="P:ConditionalExpression.IfFalse"/> property is set to default expression and
195 /// the type of the resulting <see cref="ConditionalExpression"/> returned by this method is <see cref="System.Void"/>.</returns>
196 public static ConditionalExpression IfThen(Expression test, Expression ifTrue) {
197 return Condition(test, ifTrue, Expression.Empty(), typeof(void));
201 /// Creates a <see cref="ConditionalExpression"/>.
203 /// <param name="test">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.Test"/> property equal to.</param>
204 /// <param name="ifTrue">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfTrue"/> property equal to.</param>
205 /// <param name="ifFalse">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfFalse"/> property equal to.</param>
206 /// <returns>A <see cref="ConditionalExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to
207 /// <see cref="F:ExpressionType.Conditional"/> and the <see cref="P:ConditionalExpression.Test"/>, <see cref="P:ConditionalExpression.IfTrue"/>,
208 /// and <see cref="P:ConditionalExpression.IfFalse"/> properties set to the specified values. The type of the resulting <see cref="ConditionalExpression"/>
209 /// returned by this method is <see cref="System.Void"/>.</returns>
210 public static ConditionalExpression IfThenElse(Expression test, Expression ifTrue, Expression ifFalse) {
211 return Condition(test, ifTrue, ifFalse, typeof(void));