C# 表达式树

创建表达式树

继承 Object -> Expression -> LambdaExpression -> Expression< TDelegate>

Expression 类

官方文档

  • 用于创建不同类型的表达式, 有很多方法如下面两个示例:
    • 如 Loop(Expression) 创建具有给定主体的 LoopExpression。
      • LoopExpression 表示无限循环。 可通过“中断”退出该循环。
    • GreaterThanOrEqual(Expression, Expression) 创建一个表示“大于或等于”数值比较的 BinaryExpression。
      • BinaryExpression 类 表示具有二进制运算符的表达式。
  • Lambda方法 值得注意:创建一个表示 Lambda 表达式的表达式树。返回类型是LambdaExpression
    • 参数:
    • delegateType Type:一个 Type,它表示 lambda 的委托签名。
    • body Expression:要将 Expression 属性设置为与其相等的 Body。
    • name String lambda 的名称。 用于发出调试信息。
    • tailCall Boolean 一个 Boolean,指示在编译创建的表达式时是否将应用尾调用优化。
    • parameters IEnumerable< ParameterExpression> 一个 IEnumerable< T>,包含用来填充 ParameterExpression 集合的 Parameters 对象。

Expression< TDelegate> 类

官方文档

  • 将强类型化的 Lambda 表达式表示为表达式树形式的数据结构。 此类不能被继承。
  • 作用是将参数传给LambdaExpression
  • Compile 方法
    • 将表达式树描述的 lambda 表达式编译为可执行代码,并生成表示 lambda 表达式的委托。
    • System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5;
    • Func<int, bool> deleg = expr.Compile();
  • Update

LambdaExpression

官方文档

  • 由它把我们表达式的主体,名称,以及参数保存着。
  • Compile() 方法 生成表示 lambda 表达式的委托。
  • 该 LambdaExpression 类型以表达式树的形式表示 lambda 表达式。
  • 派 Expression< TDelegate> 生 LambdaExpression 自和捕获 lambda 表达式类型的类型也可用于表示 lambda 表达式。
  • 在运行时,表示 lambda 表达式的表达式树节点始终为类型 Expression< TDelegate>。
  • NodeType属性值LambdaExpression为 Lambda.
  • 使用 Lambda 工厂方法创建对象 LambdaExpression 。

示例 循环输入10次

// 创建 loop表达式体来包含我们想要执行的代码  表示 一个循环
LoopExpression loop = Expression.Loop(
    Expression.Call(
        null,
        typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
        Expression.Constant("Hello"))
        );
 
// 创建一个代码块表达式包含我们上面创建的loop表达式,其中Expression.Block方法的参数是一个循环
BlockExpression block = Expression.Block(loop);
 
// 通过lambda方法 创建一个表示 Lambda 表达式的表达式树。
Expression<Action> lambdaExpression =  Expression.Lambda<Action>(block);
//通过Compile 方法生成表示 lambda 表达式的委托。最后通过Invoke方法调用委托
lambdaExpression.Compile().Invoke();
// 创建 loop表达式体来包含我们想要执行的代码
using System.Linq.Expressions;


//示一个标签,可以将该标签放置在任何 Expression 上下文中。 如果已跳转到该标签,则它将获取由对应的 GotoExpression 提供的值。
//否则,它接收 DefaultValue 中的值。 如果 Type 等于 System.Void,则不应提供值。
LabelTarget labelBreak = Expression.Label();

//表示一个命名的参数表达式
ParameterExpression loopIndex = Expression.Parameter(typeof(int), "index");

//创建一个 BlockExpression,其中包含给定的变量和表达式。
BlockExpression block = Expression.Block(
new[] { loopIndex },
//   创建一个表示赋值运算的 BinaryExpression。  声明了一个 初始化loopIndex =1
    Expression.Assign(loopIndex, Expression.Constant(1)),

    //1.创建 loop表达式体来包含我们想要执行的代码  表示 一个循环, 
    Expression.Loop(
        Expression.IfThenElse(
            // if 的判断逻辑
            Expression.LessThanOrEqual(loopIndex, Expression.Constant(10)),
            // 判断逻辑通过的代码
            Expression.Block(
                //Call  表达式体包含对静态方法或实例方法的调用。
                Expression.Call(
                    null,
                    typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
                    Expression.Constant("Hello")),
                Expression.PostIncrementAssign(loopIndex)),
            // 判断不通过的代码
            Expression.Break(labelBreak)
            ), labelBreak));



//   通过lambda方法 创建一个表示 Lambda 表达式的表达式树。
Expression<Action> lambdaExpression =  Expression.Lambda<Action>(block);
//通过Compile 方法生成表示 lambda 表达式的委托。最后通过Invoke方法调用委托
lambdaExpression.Compile().Invoke();


//block的Debuger View

//.Block(System.Int32 $index) {
//    $index = 1;
//    .Loop  {
//        .If($index <= 10) {
//            .Block() {
//                .Call System.Console.WriteLine("Hello");
//                $index++
//            }
//        } .Else {
//            .Break #Label1 { }
//        }
//    }
//    .LabelTarget #Label1:
//}


//Lambda方法调用后 lambdaExpression的 Debuger View

//.Lambda #Lambda1<System.Action>() {
//    .Block(System.Int32 $index) {
//        $index = 1;
//        .Loop  {
//            .If($index <= 10) {
//                .Block() {
//                    .Call System.Console.WriteLine("Hello");
//                    $index++
//                }
//        } .Else {
//                .Break #Label1 { }
//            }
//    }
//        .LabelTarget #Label1:
//    }
//}

// 直接返回常量值
ConstantExpression ce1 = Expression.Constant(10);

// 直接用我们上面创建的常量表达式来创建表达式树
Expression<Func<int>> expr1 = Expression.Lambda<Func<int>>(ce1);
Console.WriteLine(expr1.Compile().Invoke());
// 10

// --------------在方法体内创建变量,经过操作之后再返回------------------

//返回的值所在的表达式写在block的最后一个参数

// 1.创建方法体表达式 2.在方法体内声明变量并附值 3. 返回该变量
ParameterExpression param2 = Expression.Parameter(typeof(int));
BlockExpression block2 = Expression.Block(
    new[] { param2 },
    Expression.AddAssign(param2, Expression.Constant(20)),
    param2
    );
Expression<Func<int>> expr2 = Expression.Lambda<Func<int>>(block2);
Console.WriteLine(expr2.Compile().Invoke());
// 20

// -------------利用GotoExpression返回值-----------------------------------

// 创建一个 LabelTarget,它表示具有 void 类型但没有名称的标签  用于表示 GotoExpression 的目标。 
LabelTarget returnTarget = Expression.Label(typeof(Int32));


//创建一个 LabelExpression,它表示具有给定默认值的标签
//表示一个标签,可以将该标签放置在任何 Expression 上下文中。
//如果已跳转到该标签,则它将获取由对应的 GotoExpression 提供的值。
//否则,它接收 DefaultValue 中的值。 如果 Type 等于 System.Void,则不应提供值。
LabelExpression returnLabel = Expression.Label(returnTarget, Expression.Constant(100, typeof(Int32)));

// 为输入参加+10之后返回
ParameterExpression inParam3 = Expression.Parameter(typeof(int));

BlockExpression block3 = Expression.Block(
    Expression.AddAssign(inParam3, Expression.Constant(10)),
    //创建一个表示 return 语句的 GotoExpression。 可以指定在跳转时传递给标签的值。
    Expression.Return(returnTarget, inParam3),
    returnLabel
    );

Expression<Func<int, int>> expr3 = Expression.Lambda<Func<int, int>>(block3, inParam3);
Console.WriteLine(expr3.Compile().Invoke(20));
// 30


//简单的switch case 语句 来返回值

ParameterExpression genderParam = Expression.Parameter(typeof(int));
SwitchExpression switchExpression = Expression.Switch(
    genderParam,
    Expression.Constant("不详"),//默认值
    Expression.SwitchCase(Expression.Constant("男"), Expression.Constant(1)),
    Expression.SwitchCase(Expression.Constant("女"), Expression.Constant(0))
    //你可以将上面的Expression.Constant替换成其它复杂的表达式,ParameterExpression, BinaryExpression等, 这也是表达式灵活的地方,
    //因为归根结底它们都是继承自Expression, 而基本上我们用到的地方都是以基类作为参数类型接受的,所以我们可以传递任意类型的表达式。
    );
Expression<Func<int, string>> expr4 = Expression.Lambda<Func<int, string>>(switchExpression, genderParam);

遍历表达式树

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值