System.Linq.Expressions.Expression.Switch C# (CSharp) Method

Switch() public static method

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

            ReadOnlyCollection<SwitchCase> caseList = cases.ToReadOnly();
            ContractUtils.RequiresNotNullItems(caseList, nameof(cases));

            // Type of the result. Either provided, or it is type of the branches.
            Type resultType;
            if (type != null)
                resultType = type;
            else if (caseList.Count != 0)
                resultType = caseList[0].Body.Type;
            else if (defaultBody != null)
                resultType = defaultBody.Type;
            else
                resultType = typeof(void);
            bool customType = type != null;

            if (comparison != null)
            {
                ParameterInfo[] pms = comparison.GetParametersCached();
                if (pms.Length != 2)
                {
                    throw Error.IncorrectNumberOfMethodCallArguments(comparison, nameof(comparison));
                }
                // Validate that the switch value's type matches the comparison method's
                // left hand side parameter type.
                ParameterInfo 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);
                    }
                }

                ParameterInfo rightParam = pms[1];
                foreach (SwitchCase c in caseList)
                {
                    ContractUtils.RequiresNotNull(c, nameof(cases));
                    ValidateSwitchCaseType(c.Body, customType, resultType, nameof(cases));
                    for (int i = 0, n = c.TestValues.Count; i < n; 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);
                        }
                    }
                }

                // if we have a non-boolean user-defined equals, we don't want it.
                if (comparison.ReturnType != typeof(bool))
                {
                    throw Error.EqualityMustReturnBoolean(comparison, nameof(comparison));
                }
            }
            else if (caseList.Count != 0)
            {
                // 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.
                Expression firstTestValue = caseList[0].TestValues[0];
                foreach (SwitchCase c in caseList)
                {
                    ContractUtils.RequiresNotNull(c, nameof(cases));
                    ValidateSwitchCaseType(c.Body, customType, resultType, nameof(cases));
                    // When no comparison method is provided, require all test values to have the same type.
                    for (int i = 0, n = c.TestValues.Count; i < n; i++)
                    {
                        if (!TypeUtils.AreEquivalent(firstTestValue.Type, c.TestValues[i].Type))
                        {
                            throw Error.AllTestValuesMustHaveSameType(nameof(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.
                BinaryExpression 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(nameof(defaultBody));
            }
            else
            {
                ValidateSwitchCaseType(defaultBody, customType, resultType, nameof(defaultBody));
            }

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

Same methods

Expression::Switch ( Expression switchValue ) : SwitchExpression
Expression::Switch ( Expression switchValue, Expression defaultBody ) : SwitchExpression
Expression::Switch ( Expression switchValue, Expression defaultBody, MethodInfo comparison ) : SwitchExpression
Expression::Switch ( Expression switchValue, Expression defaultBody, MethodInfo comparison, IEnumerable cases ) : SwitchExpression
Expression::Switch ( Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison ) : SwitchExpression

Usage Example

Ejemplo n.º 1
0
        private static LinqExpression Compile(ElementExpression value, CompilationData data)
        {
            data.Cache ??= new Dictionary <CachedExpression, ParameterExpression>();
            data.GroupCache ??= new Dictionary <ExpressionGroup, LinqExpression[]>();
            switch (value)
            {
            case ICLRExpression s:
                return(s.Compile(e => Compile(e, data)));

            case Constant c:
                return(LinqExpression.Constant(c.Value));

            case Binary b:
                var ea = Compile(b.OpA, data);
                var eb = Compile(b.OpB, data);
                if (b.Operation == Binary.Op.Pow)
                {
                    var o = LinqExpression.Call(typeof(Math).GetMethod(nameof(Math.Pow)),
                                                LinqExpression.Convert(ea, typeof(double)), LinqExpression.Convert(eb, typeof(double)));
                    return(LinqExpression.Convert(o, typeof(float)));
                }

                if (b.Operation == Binary.Op.Atan2)
                {
                    var o = LinqExpression.Call(typeof(Math).GetMethod(nameof(Math.Atan2)),
                                                LinqExpression.Convert(ea, typeof(double)), LinqExpression.Convert(eb, typeof(double)));
                    return(LinqExpression.Convert(o, typeof(float)));
                }

                return(BinaryOps[b.Operation](ea, eb));

            case Unary u:
                var input  = Compile(u.Operand, data);
                var output = LinqExpression.Call(MethodOps[u.Operation], LinqExpression.Convert(input, typeof(double)));
                return(LinqExpression.Convert(output, typeof(float)));

            case CachedExpression v:
                if (!data.Cache.TryGetValue(v, out var varExpr))
                {
                    var result = Compile(v.Value, data);
                    data.Cache.Add(v, varExpr = LinqExpression.Parameter(result.Type));
                    data.Statements.Add(LinqExpression.Assign(varExpr, result));
                    data.Variables.Add(varExpr);
                }

                return(varExpr);

            case Mux m:
                if (m.Operands.Count == 2)
                {
                    return(LinqExpression.Condition(
                               LinqExpression.LessThan(Compile(m.Selector, data), LinqExpression.Constant(1f)),
                               Compile(m.Operands[0], data), Compile(m.Operands[1], data)));
                }

                var sel        = LinqExpression.Convert(Compile(m.Selector, data), typeof(int));
                var clampedSel =
                    LinqExpression.Condition(
                        LinqExpression.GreaterThanOrEqual(sel, LinqExpression.Constant(m.Operands.Count)),
                        LinqExpression.Constant(m.Operands.Count - 1), sel);
                var cases = m.Operands.Select(
                    (c, i) => LinqExpression.SwitchCase(Compile(c, data), LinqExpression.Constant(i)))
                            .ToArray();
                return(LinqExpression.Switch(clampedSel, cases[0].Body, cases));

            case State s:
                if (data.ResolveState == null)
                {
                    throw new Exception("Tried to compile a State expression outside of an ExpressionGroup");
                }

                return(data.ResolveState(s));

            case ExpressionGroupElement groupElement:
                if (!data.GroupCache.TryGetValue(groupElement.Group, out var groupList))
                {
                    data.GroupCache.Add(groupElement.Group, groupList = CompileGroup(groupElement.Group, data));
                }

                return(groupList[groupElement.Index]);
            }

            throw new Exception("Unknown expression " + value);
        }
All Usage Examples Of System.Linq.Expressions.Expression::Switch
Expression