#if NET20 || NET30 || !NET_4_6 // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Diagnostics; using System.Dynamic.Utils; using LinqInternal.Core; namespace System.Linq.Expressions.Reimplement { /// /// Represents an expression that has a conditional operator. /// [DebuggerTypeProxy(typeof(ConditionalExpressionProxy))] public class ConditionalExpression : Expression { private readonly Expression _test; private readonly Expression _true; internal ConditionalExpression(Expression test, Expression ifTrue) { _test = test; _true = ifTrue; } internal static ConditionalExpression Make(Expression test, Expression ifTrue, Expression ifFalse, Type type) { if (ifTrue.Type != type || ifFalse.Type != type) { return new FullConditionalExpressionWithType(test, ifTrue, ifFalse, type); } if (ifFalse is DefaultExpression && ifFalse.Type == typeof(void)) { return new ConditionalExpression(test, ifTrue); } else { return new FullConditionalExpression(test, ifTrue, ifFalse); } } /// /// Returns the node type of this Expression. Extension nodes should return /// ExpressionType.Extension when overriding this method. /// /// The of the expression. public sealed override ExpressionType NodeType { get { return ExpressionType.Conditional; } } /// /// Gets the static type of the expression that this represents. /// /// The that represents the static type of the expression. public override Type Type { get { return IfTrue.Type; } } /// /// Gets the test of the conditional operation. /// public Expression Test { get { return _test; } } /// /// Gets the expression to execute if the test evaluates to true. /// public Expression IfTrue { get { return _true; } } /// /// Gets the expression to execute if the test evaluates to false. /// public Expression IfFalse { get { return GetFalse(); } } internal virtual Expression GetFalse() { return Empty(); } protected internal override Expression Accept(ExpressionVisitor visitor) { return visitor.VisitConditional(this); } /// /// Creates a new expression that is like this one, but using the /// supplied children. If all of the children are the same, it will /// return this expression. /// /// The property of the result. /// The property of the result. /// The property of the result. /// This expression if no children changed, or an expression with the updated children. public ConditionalExpression Update(Expression test, Expression ifTrue, Expression ifFalse) { if (test == Test && ifTrue == IfTrue && ifFalse == IfFalse) { return this; } return Condition(test, ifTrue, ifFalse, Type); } } internal class FullConditionalExpression : ConditionalExpression { private readonly Expression _false; internal FullConditionalExpression(Expression test, Expression ifTrue, Expression ifFalse) : base(test, ifTrue) { _false = ifFalse; } internal override Expression GetFalse() { return _false; } } internal class FullConditionalExpressionWithType : FullConditionalExpression { private readonly Type _type; internal FullConditionalExpressionWithType(Expression test, Expression ifTrue, Expression ifFalse, Type type) : base(test, ifTrue, ifFalse) { _type = type; } public sealed override Type Type { get { return _type; } } } public partial class Expression { /// /// Creates a . /// /// An to set the property equal to. /// An to set the property equal to. /// An to set the property equal to. /// A that has the property equal to /// and the , , /// and properties set to the specified values. public static ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse) { RequiresCanRead(test, "test"); RequiresCanRead(ifTrue, "ifTrue"); RequiresCanRead(ifFalse, "ifFalse"); if (test.Type != typeof(bool)) { throw Error.ArgumentMustBeBoolean(); } if (ifTrue.Type != ifFalse.Type) { throw Error.ArgumentTypesMustMatch(); } return ConditionalExpression.Make(test, ifTrue, ifFalse, ifTrue.Type); } /// /// Creates a . /// /// An to set the property equal to. /// An to set the property equal to. /// An to set the property equal to. /// A to set the property equal to. /// A that has the property equal to /// and the , , /// and properties set to the specified values. /// This method allows explicitly unifying the result type of the conditional expression in cases where the types of /// and expressions are not equal. Types of both and must be implicitly /// reference assignable to the result type. The is allowed to be . public static ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse, Type type) { RequiresCanRead(test, "test"); RequiresCanRead(ifTrue, "ifTrue"); RequiresCanRead(ifFalse, "ifFalse"); ContractUtils.RequiresNotNull(type, "type"); if (test.Type != typeof(bool)) { throw Error.ArgumentMustBeBoolean(); } if (type != typeof(void)) { if (!TypeHelper.AreReferenceAssignable(type, ifTrue.Type) || !TypeHelper.AreReferenceAssignable(type, ifFalse.Type)) { throw Error.ArgumentTypesMustMatch(); } } return ConditionalExpression.Make(test, ifTrue, ifFalse, type); } /// /// Creates a . /// /// An to set the property equal to. /// An to set the property equal to. /// A that has the property equal to /// and the , , /// properties set to the specified values. The property is set to default expression and /// the type of the resulting returned by this method is . public static ConditionalExpression IfThen(Expression test, Expression ifTrue) { return Condition(test, ifTrue, Empty(), typeof(void)); } /// /// Creates a . /// /// An to set the property equal to. /// An to set the property equal to. /// An to set the property equal to. /// A that has the property equal to /// and the , , /// and properties set to the specified values. The type of the resulting /// returned by this method is . public static ConditionalExpression IfThenElse(Expression test, Expression ifTrue, Expression ifFalse) { return Condition(test, ifTrue, ifFalse, typeof(void)); } } } #endif