Expression Tree Practice: C# Conditional Statements

2019年12月15日 3664点热度 0人点赞 4条评论
内容目录

Expression Tree Practice: C# Conditional Statements

[TOC]

Conditional Statements

C# provides the following types of conditional statements:

Statement Description
if An if statement consists of a boolean expression followed by one or more statements.
if...else An if statement can be followed by an optional else statement, which executes when the boolean expression is false.
Nested if statements You can use another if or else if statement within an if or else if statement.
switch statement A switch statement allows testing a variable against multiple values.
Nested switch statements You can use another switch statement within a switch statement.

Of course, there are also ??, ?:, and other conditionals, which will be detailed in practice below.

if

The if statement is expressed using IfThen(Expression test, Expression ifTrue);

Expression test represents the expression used for judgment, and Expression ifTrue represents the expression tree that executes when the result is true.

Example

            int a = 10;
            int b = 10;
        if (a == b)
        {
            Console.WriteLine("a == b is true; the statement is executed");
        }

        Console.ReadKey();</code></pre>

Implementing this using expression trees is as follows:

            ParameterExpression a = Expression.Variable(typeof(int), "a");
            ParameterExpression b = Expression.Variable(typeof(int), "b");
            MethodCallExpression call = Expression.Call(
                null,
                typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
                Expression.Constant("a == b is true; the expression tree is executed"));
        ConditionalExpression _if = Expression.IfThen(Expression.Equal(a, b), call);

        Expression&lt;Action&lt;int, int&gt;&gt; lambda = Expression.Lambda&lt;Action&lt;int, int&gt;&gt;(_if, a, b);
        lambda.Compile()(10, 10);

        Console.ReadKey();</code></pre>

The generated expression tree is as follows:

.Lambda #Lambda1<System.Action`2[System.Int32,System.Int32]>(
    System.Int32 $a,
    System.Int32 $b) {
    .If ($a == $b) {
        .Call System.Console.WriteLine("a == b is true; the expression tree is executed")
    } .Else {
        .Default(System.Void)
    }
}

if...else

The if...else is represented using the following expression tree:

 ConditionalExpression IfThenElse(Expression test, Expression ifTrue, Expression ifFalse);

Example code is as follows:

            int a = 10;
            int b = 11;
        if (a == b)
        {
            Console.WriteLine(&quot;a == b is true; this statement is executed&quot;);
        }
        else
        {
            Console.WriteLine(&quot;a == b is false; this statement is executed&quot;);
        }
        Console.ReadKey();</code></pre>

Implementing this using expression trees is as follows:

            ParameterExpression a = Expression.Variable(typeof(int), "a");
            ParameterExpression b = Expression.Variable(typeof(int), "b");
            MethodCallExpression call1 = Expression.Call(
                null,
                typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
                Expression.Constant("a == b is true; this expression tree is executed"));
        MethodCallExpression call2 = Expression.Call(
            null,
            typeof(Console).GetMethod(&quot;WriteLine&quot;, new Type[] { typeof(string) }),
            Expression.Constant(&quot;a == b is false; this expression tree is executed&quot;));

        ConditionalExpression _if = Expression.IfThenElse(Expression.Equal(a, b), call1, call2);

        Expression&lt;Action&lt;int, int&gt;&gt; lambda = Expression.Lambda&lt;Action&lt;int, int&gt;&gt;(_if, a, b);
        lambda.Compile()(10, 11);

        Console.ReadKey();</code></pre>

The generated expression tree is as follows:

.Lambda #Lambda1<System.Action`2[System.Int32,System.Int32]>(
    System.Int32 $a,
    System.Int32 $b) {
    .If ($a == $b) {
        .Call System.Console.WriteLine("a == b is true; this expression tree is executed")
    } .Else {
        .Call System.Console.WriteLine("a == b is false; this expression tree is executed")
    }
}

switch

Example code is as follows:

            int a = 2;
            switch (a)
            {
                case 1: Console.WriteLine("a == 1"); break;
                case 2: Console.WriteLine("a == 2"); break;
                default: Console.WriteLine("a != 1 && a == 2");
            }
        Console.ReadKey();</code></pre>

Each case is represented using the SwitchCase type and is generated using Expression.SwitchCase.

Expression.Switch is used to construct a switch expression tree.

There are many overloads for Expression.Switch, but the common form is:

SwitchExpression Switch(Expression switchValue, Expression defaultBody, params SwitchCase[] cases);

switchValue represents the input parameter;

defaultBody represents the expression executed for default;

cases represents multiple case clauses.

The above code can be rewritten using expression trees as follows:

            ParameterExpression a = Expression.Parameter(typeof(int), "a");
            MethodCallExpression _default = Expression.Call(
                null,
                typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
                Expression.Constant("a != 1 && a == 2"));
        SwitchCase case1 = Expression.SwitchCase(
            Expression.Call(null,
            typeof(Console).GetMethod(&quot;WriteLine&quot;, new Type[] { typeof(string) }),
            Expression.Constant(&quot;a == 1&quot;)),
            new ConstantExpression[] { Expression.Constant(1) }
            );

        SwitchCase case2 = Expression.SwitchCase(
            Expression.Call(null,
            typeof(Console).GetMethod(&quot;WriteLine&quot;, new Type[] { typeof(string) }),
            Expression.Constant(&quot;a == 2&quot;)),
            new ConstantExpression[] { Expression.Constant(2) }
            );

        SwitchExpression _switch = Expression.Switch(a, _default, new SwitchCase[] { case1, case2 });
        Expression&lt;Action&lt;int&gt;&gt; lambda = Expression.Lambda&lt;Action&lt;int&gt;&gt;(_switch, a);
        lambda.Compile()(1);

        Console.ReadKey();</code></pre>

The generated expression tree is as follows:

.Lambda #Lambda1<System.Action`1[System.Int32]>(System.Int32 $a) {
    .Switch ($a) {
    .Case (1):
            .Call System.Console.WriteLine("a == 1")
    .Case (2):
            .Call System.Console.WriteLine("a == 2")
    .Default:
            .Call System.Console.WriteLine("a != 1 && a == 2")
    }
}

Interestingly, there is no break, yet the expression tree is normal and runs without issues.

?? and ?:

?? represents the null-coalescing operator, for example, a ?? b, which returns a if a is not null; otherwise, it returns b;

The common definition is:

BinaryExpression Coalesce(Expression left, Expression right)

This will not be elaborated further.

?: is the ternary operator, for example, a > b ? a : b.

The common definition is:

ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse)

Refer to the previously mentioned if...else expression tree; this will not be elaborated further.

痴者工良

高级程序员劝退师

文章评论