SwitchExpression.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / Microsoft / Scripting / Ast / SwitchExpression.cs / 1305376 / SwitchExpression.cs

                            /* **************************************************************************** 
 *
 * Copyright (c) Microsoft Corporation.
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/ 

using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Diagnostics;
using System.Dynamic.Utils; 
using System.Reflection;

#if SILVERLIGHT
using System.Core; 
#endif
 
namespace System.Linq.Expressions { 
    /// 
    /// Represents a control expression that handles multiple selections by passing control to a . 
    /// 
#if !SILVERLIGHT
    [DebuggerTypeProxy(typeof(Expression.SwitchExpressionProxy))]
#endif 
    public sealed class SwitchExpression : Expression {
        private readonly Type _type; 
        private readonly Expression _switchValue; 
        private readonly ReadOnlyCollection _cases;
        private readonly Expression _defaultBody; 
        private readonly MethodInfo _comparison;

        internal SwitchExpression(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, ReadOnlyCollection cases) {
            _type = type; 
            _switchValue = switchValue;
            _defaultBody = defaultBody; 
            _comparison = comparison; 
            _cases = cases;
        } 

        /// 
        /// Gets the static type of the expression that this  represents.
        ///  
        /// The  that represents the static type of the expression.
        public sealed override Type Type { 
            get { return _type; } 
        }
 
        /// 
        /// 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.Switch; } 
        }
 
        /// 
        /// Gets the test for the switch.
        /// 
        public Expression SwitchValue { 
            get { return _switchValue; }
        } 
 
        /// 
        /// Gets the collection of  objects for the switch. 
        /// 
        public ReadOnlyCollection Cases {
            get { return _cases; }
        } 

        ///  
        /// Gets the test for the switch. 
        /// 
        public Expression DefaultBody { 
            get { return _defaultBody; }
        }

        ///  
        /// Gets the equality comparison method, if any.
        ///  
        public MethodInfo Comparison { 
            get { return _comparison; }
        } 

        /// 
        /// Dispatches to the specific visit method for this node type.
        ///  
        protected internal override Expression Accept(ExpressionVisitor visitor) {
            return visitor.VisitSwitch(this); 
        } 

        internal bool IsLifted { 
            get {
                if (_switchValue.Type.IsNullableType()) {
                    return (_comparison == null) ||
                        !TypeUtils.AreEquivalent(_switchValue.Type, _comparison.GetParametersCached()[0].ParameterType.GetNonRefType()); 
                }
                return false; 
            } 
        }
 
        /// 
        /// 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 SwitchExpression Update(Expression switchValue, IEnumerable cases, Expression defaultBody) {
            if (switchValue == SwitchValue && cases == Cases && defaultBody == DefaultBody) {
                return this;
            } 
            return Expression.Switch(Type, switchValue, defaultBody, Comparison, cases);
        } 
    } 

    public partial class Expression { 
        /// 
        /// Creates a .
        /// 
        /// The value to be tested against each case. 
        /// The valid cases for this switch.
        /// The created . 
        public static SwitchExpression Switch(Expression switchValue, params SwitchCase[] cases) { 
            return Switch(switchValue, null, null, (IEnumerable)cases);
        } 

        /// 
        /// Creates a .
        ///  
        /// The value to be tested against each case.
        /// The result of the switch if no cases are matched. 
        /// The valid cases for this switch. 
        /// The created .
        public static SwitchExpression Switch(Expression switchValue, Expression defaultBody, params SwitchCase[] cases) { 
            return Switch(switchValue, defaultBody, null, (IEnumerable)cases);
        }

        ///  
        /// Creates a .
        ///  
        /// The value to be tested against each case. 
        /// The result of the switch if no cases are matched.
        /// The equality comparison method to use. 
        /// The valid cases for this switch.
        /// The created .
        public static SwitchExpression Switch(Expression switchValue, Expression defaultBody, MethodInfo comparison, params SwitchCase[] cases) {
            return Switch(switchValue, defaultBody, comparison, (IEnumerable)cases); 
        }
 
        ///  
        /// Creates a .
        ///  
        /// The result type of the switch.
        /// The value to be tested against each case.
        /// The result of the switch if no cases are matched.
        /// The equality comparison method to use. 
        /// The valid cases for this switch.
        /// The created . 
        public static SwitchExpression Switch(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, params SwitchCase[] cases) { 
            return Switch(type, switchValue, defaultBody, comparison, (IEnumerable)cases);
        } 

        /// 
        /// Creates a .
        ///  
        /// The value to be tested against each case.
        /// The result of the switch if no cases are matched. 
        /// The equality comparison method to use. 
        /// The valid cases for this switch.
        /// The created . 
        public static SwitchExpression Switch(Expression switchValue, Expression defaultBody, MethodInfo comparison, IEnumerable cases) {
            return Switch(null, switchValue, defaultBody, comparison, cases);
        }
 
        /// 
        /// Creates a . 
        ///  
        /// The result type of the switch.
        /// The value to be tested against each case. 
        /// The result of the switch if no cases are matched.
        /// The equality comparison method to use.
        /// The valid cases for this switch.
        /// The created . 
        public static SwitchExpression Switch(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, IEnumerable cases) {
            RequiresCanRead(switchValue, "switchValue"); 
            if (switchValue.Type == typeof(void)) throw Error.ArgumentCannotBeOfTypeVoid(); 

            var caseList = cases.ToReadOnly(); 
            ContractUtils.RequiresNotEmpty(caseList, "cases");
            ContractUtils.RequiresNotNullItems(caseList, "cases");

            // Type of the result. Either provided, or it is type of the branches. 
            Type resultType = type ?? caseList[0].Body.Type;
            bool customType = type != null; 
 
            if (comparison != null) {
                var pms = comparison.GetParametersCached(); 
                if (pms.Length != 2) {
                    throw Error.IncorrectNumberOfMethodCallArguments(comparison);
                }
                // Validate that the switch value's type matches the comparison method's 
                // left hand side parameter type.
                var leftParam = pms[0]; 
                bool liftedCall = false; 
                if (!ParameterIsAssignable(leftParam, switchValue.Type)) {
                    liftedCall = ParameterIsAssignable(leftParam, switchValue.Type.GetNonNullableType()); 
                    if (!liftedCall) {
                        throw Error.SwitchValueTypeDoesNotMatchComparisonMethodParameter(switchValue.Type, leftParam.ParameterType);
                    }
                } 

                var rightParam = pms[1]; 
                foreach (var c in caseList) { 
                    ContractUtils.RequiresNotNull(c, "cases");
                    ValidateSwitchCaseType(c.Body, customType, resultType, "cases"); 
                    for (int i = 0; i < c.TestValues.Count; i++) {
                        // When a comparison method is provided, test values can have different type but have to
                        // be reference assignable to the right hand side parameter of the method.
                        Type rightOperandType = c.TestValues[i].Type; 
                        if (liftedCall) {
                            if (!rightOperandType.IsNullableType()) { 
                                throw Error.TestValueTypeDoesNotMatchComparisonMethodParameter(rightOperandType, rightParam.ParameterType); 
                            }
                            rightOperandType = rightOperandType.GetNonNullableType(); 
                        }
                        if (!ParameterIsAssignable(rightParam, rightOperandType)) {
                            throw Error.TestValueTypeDoesNotMatchComparisonMethodParameter(rightOperandType, rightParam.ParameterType);
                        } 
                    }
                } 
            } else { 
                // When comparison method is not present, all the test values must have
                // the same type. Use the first test value's type as the baseline. 
                var firstTestValue = caseList[0].TestValues[0];
                foreach (var c in caseList) {
                    ContractUtils.RequiresNotNull(c, "cases");
                    ValidateSwitchCaseType(c.Body, customType, resultType, "cases"); 
                    // When no comparison method is provided, require all test values to have the same type.
                    for (int i = 0; i < c.TestValues.Count; i++) { 
                        if (!TypeUtils.AreEquivalent(firstTestValue.Type, c.TestValues[i].Type)) { 
                            throw new ArgumentException(Strings.AllTestValuesMustHaveSameType, "cases");
                        } 
                    }
                }

                // Now we need to validate that switchValue.Type and testValueType 
                // make sense in an Equal node. Fortunately, Equal throws a
                // reasonable error, so just call it. 
                var equal = Equal(switchValue, firstTestValue, false, comparison); 

                // Get the comparison function from equals node. 
                comparison = equal.Method;
            }

            if (defaultBody == null) { 
                if (resultType != typeof(void)) throw Error.DefaultBodyMustBeSupplied();
            } else { 
                ValidateSwitchCaseType(defaultBody, customType, resultType, "defaultBody"); 
            }
 
            // if we have a non-boolean userdefined equals, we don't want it.
            if (comparison != null && comparison.ReturnType != typeof(bool)) {
                throw Error.EqualityMustReturnBoolean(comparison);
            } 

            return new SwitchExpression(resultType, switchValue, defaultBody, comparison, caseList); 
        } 

 
        /// 
        /// If custom type is provided, all branches must be reference assignable to the result type.
        /// If no custom type is provided, all branches must have the same type - resultType.
        ///  
        private static void ValidateSwitchCaseType(Expression @case, bool customType, Type resultType, string parameterName) {
            if (customType) { 
                if (resultType != typeof(void)) { 
                    if (!TypeUtils.AreReferenceAssignable(resultType, @case.Type)) {
                        throw new ArgumentException(Strings.ArgumentTypesMustMatch, parameterName); 
                    }
                }
            } else {
                if (!TypeUtils.AreEquivalent(resultType, @case.Type)) { 
                    throw new ArgumentException(Strings.AllCaseBodiesMustHaveSameType, parameterName);
                } 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
/* **************************************************************************** 
 *
 * Copyright (c) Microsoft Corporation.
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/ 

using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Diagnostics;
using System.Dynamic.Utils; 
using System.Reflection;

#if SILVERLIGHT
using System.Core; 
#endif
 
namespace System.Linq.Expressions { 
    /// 
    /// Represents a control expression that handles multiple selections by passing control to a . 
    /// 
#if !SILVERLIGHT
    [DebuggerTypeProxy(typeof(Expression.SwitchExpressionProxy))]
#endif 
    public sealed class SwitchExpression : Expression {
        private readonly Type _type; 
        private readonly Expression _switchValue; 
        private readonly ReadOnlyCollection _cases;
        private readonly Expression _defaultBody; 
        private readonly MethodInfo _comparison;

        internal SwitchExpression(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, ReadOnlyCollection cases) {
            _type = type; 
            _switchValue = switchValue;
            _defaultBody = defaultBody; 
            _comparison = comparison; 
            _cases = cases;
        } 

        /// 
        /// Gets the static type of the expression that this  represents.
        ///  
        /// The  that represents the static type of the expression.
        public sealed override Type Type { 
            get { return _type; } 
        }
 
        /// 
        /// 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.Switch; } 
        }
 
        /// 
        /// Gets the test for the switch.
        /// 
        public Expression SwitchValue { 
            get { return _switchValue; }
        } 
 
        /// 
        /// Gets the collection of  objects for the switch. 
        /// 
        public ReadOnlyCollection Cases {
            get { return _cases; }
        } 

        ///  
        /// Gets the test for the switch. 
        /// 
        public Expression DefaultBody { 
            get { return _defaultBody; }
        }

        ///  
        /// Gets the equality comparison method, if any.
        ///  
        public MethodInfo Comparison { 
            get { return _comparison; }
        } 

        /// 
        /// Dispatches to the specific visit method for this node type.
        ///  
        protected internal override Expression Accept(ExpressionVisitor visitor) {
            return visitor.VisitSwitch(this); 
        } 

        internal bool IsLifted { 
            get {
                if (_switchValue.Type.IsNullableType()) {
                    return (_comparison == null) ||
                        !TypeUtils.AreEquivalent(_switchValue.Type, _comparison.GetParametersCached()[0].ParameterType.GetNonRefType()); 
                }
                return false; 
            } 
        }
 
        /// 
        /// 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 SwitchExpression Update(Expression switchValue, IEnumerable cases, Expression defaultBody) {
            if (switchValue == SwitchValue && cases == Cases && defaultBody == DefaultBody) {
                return this;
            } 
            return Expression.Switch(Type, switchValue, defaultBody, Comparison, cases);
        } 
    } 

    public partial class Expression { 
        /// 
        /// Creates a .
        /// 
        /// The value to be tested against each case. 
        /// The valid cases for this switch.
        /// The created . 
        public static SwitchExpression Switch(Expression switchValue, params SwitchCase[] cases) { 
            return Switch(switchValue, null, null, (IEnumerable)cases);
        } 

        /// 
        /// Creates a .
        ///  
        /// The value to be tested against each case.
        /// The result of the switch if no cases are matched. 
        /// The valid cases for this switch. 
        /// The created .
        public static SwitchExpression Switch(Expression switchValue, Expression defaultBody, params SwitchCase[] cases) { 
            return Switch(switchValue, defaultBody, null, (IEnumerable)cases);
        }

        ///  
        /// Creates a .
        ///  
        /// The value to be tested against each case. 
        /// The result of the switch if no cases are matched.
        /// The equality comparison method to use. 
        /// The valid cases for this switch.
        /// The created .
        public static SwitchExpression Switch(Expression switchValue, Expression defaultBody, MethodInfo comparison, params SwitchCase[] cases) {
            return Switch(switchValue, defaultBody, comparison, (IEnumerable)cases); 
        }
 
        ///  
        /// Creates a .
        ///  
        /// The result type of the switch.
        /// The value to be tested against each case.
        /// The result of the switch if no cases are matched.
        /// The equality comparison method to use. 
        /// The valid cases for this switch.
        /// The created . 
        public static SwitchExpression Switch(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, params SwitchCase[] cases) { 
            return Switch(type, switchValue, defaultBody, comparison, (IEnumerable)cases);
        } 

        /// 
        /// Creates a .
        ///  
        /// The value to be tested against each case.
        /// The result of the switch if no cases are matched. 
        /// The equality comparison method to use. 
        /// The valid cases for this switch.
        /// The created . 
        public static SwitchExpression Switch(Expression switchValue, Expression defaultBody, MethodInfo comparison, IEnumerable cases) {
            return Switch(null, switchValue, defaultBody, comparison, cases);
        }
 
        /// 
        /// Creates a . 
        ///  
        /// The result type of the switch.
        /// The value to be tested against each case. 
        /// The result of the switch if no cases are matched.
        /// The equality comparison method to use.
        /// The valid cases for this switch.
        /// The created . 
        public static SwitchExpression Switch(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, IEnumerable cases) {
            RequiresCanRead(switchValue, "switchValue"); 
            if (switchValue.Type == typeof(void)) throw Error.ArgumentCannotBeOfTypeVoid(); 

            var caseList = cases.ToReadOnly(); 
            ContractUtils.RequiresNotEmpty(caseList, "cases");
            ContractUtils.RequiresNotNullItems(caseList, "cases");

            // Type of the result. Either provided, or it is type of the branches. 
            Type resultType = type ?? caseList[0].Body.Type;
            bool customType = type != null; 
 
            if (comparison != null) {
                var pms = comparison.GetParametersCached(); 
                if (pms.Length != 2) {
                    throw Error.IncorrectNumberOfMethodCallArguments(comparison);
                }
                // Validate that the switch value's type matches the comparison method's 
                // left hand side parameter type.
                var leftParam = pms[0]; 
                bool liftedCall = false; 
                if (!ParameterIsAssignable(leftParam, switchValue.Type)) {
                    liftedCall = ParameterIsAssignable(leftParam, switchValue.Type.GetNonNullableType()); 
                    if (!liftedCall) {
                        throw Error.SwitchValueTypeDoesNotMatchComparisonMethodParameter(switchValue.Type, leftParam.ParameterType);
                    }
                } 

                var rightParam = pms[1]; 
                foreach (var c in caseList) { 
                    ContractUtils.RequiresNotNull(c, "cases");
                    ValidateSwitchCaseType(c.Body, customType, resultType, "cases"); 
                    for (int i = 0; i < c.TestValues.Count; i++) {
                        // When a comparison method is provided, test values can have different type but have to
                        // be reference assignable to the right hand side parameter of the method.
                        Type rightOperandType = c.TestValues[i].Type; 
                        if (liftedCall) {
                            if (!rightOperandType.IsNullableType()) { 
                                throw Error.TestValueTypeDoesNotMatchComparisonMethodParameter(rightOperandType, rightParam.ParameterType); 
                            }
                            rightOperandType = rightOperandType.GetNonNullableType(); 
                        }
                        if (!ParameterIsAssignable(rightParam, rightOperandType)) {
                            throw Error.TestValueTypeDoesNotMatchComparisonMethodParameter(rightOperandType, rightParam.ParameterType);
                        } 
                    }
                } 
            } else { 
                // When comparison method is not present, all the test values must have
                // the same type. Use the first test value's type as the baseline. 
                var firstTestValue = caseList[0].TestValues[0];
                foreach (var c in caseList) {
                    ContractUtils.RequiresNotNull(c, "cases");
                    ValidateSwitchCaseType(c.Body, customType, resultType, "cases"); 
                    // When no comparison method is provided, require all test values to have the same type.
                    for (int i = 0; i < c.TestValues.Count; i++) { 
                        if (!TypeUtils.AreEquivalent(firstTestValue.Type, c.TestValues[i].Type)) { 
                            throw new ArgumentException(Strings.AllTestValuesMustHaveSameType, "cases");
                        } 
                    }
                }

                // Now we need to validate that switchValue.Type and testValueType 
                // make sense in an Equal node. Fortunately, Equal throws a
                // reasonable error, so just call it. 
                var equal = Equal(switchValue, firstTestValue, false, comparison); 

                // Get the comparison function from equals node. 
                comparison = equal.Method;
            }

            if (defaultBody == null) { 
                if (resultType != typeof(void)) throw Error.DefaultBodyMustBeSupplied();
            } else { 
                ValidateSwitchCaseType(defaultBody, customType, resultType, "defaultBody"); 
            }
 
            // if we have a non-boolean userdefined equals, we don't want it.
            if (comparison != null && comparison.ReturnType != typeof(bool)) {
                throw Error.EqualityMustReturnBoolean(comparison);
            } 

            return new SwitchExpression(resultType, switchValue, defaultBody, comparison, caseList); 
        } 

 
        /// 
        /// If custom type is provided, all branches must be reference assignable to the result type.
        /// If no custom type is provided, all branches must have the same type - resultType.
        ///  
        private static void ValidateSwitchCaseType(Expression @case, bool customType, Type resultType, string parameterName) {
            if (customType) { 
                if (resultType != typeof(void)) { 
                    if (!TypeUtils.AreReferenceAssignable(resultType, @case.Type)) {
                        throw new ArgumentException(Strings.ArgumentTypesMustMatch, parameterName); 
                    }
                }
            } else {
                if (!TypeUtils.AreEquivalent(resultType, @case.Type)) { 
                    throw new ArgumentException(Strings.AllCaseBodiesMustHaveSameType, parameterName);
                } 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK