环球快报:C#表达式树

2023-05-03 13:34:03 来源:博客园

C# 表达式树是 .NET 框架中的一项强大的功能,我们可以利用表达式树来动态生成 lambda 表达式和 LINQ 查询语句,这极大的方便了我们动态构建数据查询和过滤的逻辑。本文将从基本用法和高级用法两个方面来介绍 C# 表达式树。

基本用法

首先,我们需要了解Expression类型,这个类型是所有表达式树节点的基类,表达式树常用的基本节点类型还有ConstantExpressionParameterExpressionBinaryExpressionLambdaExpression等。下面是一个基本的例子:


(资料图片仅供参考)

using System;using System.Linq.Expressions;namespace ExpressionDemo{    internal class Program    {        static void Main(string[] args)        {            // 创建参数和常量表达式            ParameterExpression a = Expression.Parameter(typeof(int), "a");            ConstantExpression b = Expression.Constant(2);            // 创建加法表达式            BinaryExpression c = Expression.Add(a, b);            // 创建函数表达式            Expression> func = Expression.Lambda>(c, a);            // 执行以 (a + 2) 为表达式的函数            Func compiledFunc = func.Compile();            Console.WriteLine(compiledFunc(1)); // 输出 3        }    }}

首先,我们创建了一个ParameterExpression类型的变量a和一个ConstantExpression类型的常量b。接着,我们定义了一个 “加法表达式”c,将ab相加并返回。然后,我们使用 lambda 表达式将c作为函数体并传入了参数变量a,返回类型为int,即Expression>。现在,我们可以使用func.Compile()将 lambda 表达式编译成可以直接调用的函数,并传入参数1调用该函数,实现了以(a + 2)为表达式的函数。最后,我们输出函数的结果3

此外,我们还可以使用表达式树来构造 LINQ 查询语句,并执行查询和筛选。例如,我们可以使用表达式树来动态生成针对List中存储的对象的查询:

using System;using System.Collections.Generic;using System.Linq;using System.Linq.Expressions;namespace ExpressionDemo{    class Person    {        public int Age { get; set; }        public string Name { get; set; }    }    internal class Program    {        static void Main(string[] args)        {            // 构建一个 Person 列表            List people = new List            {                new Person { Name = "Tom", Age = 23 },                new Person { Name = "John", Age = 32 },                new Person { Name = "Karen", Age = 28 }            };            // 动态构建查询表达式            ParameterExpression p = Expression.Parameter(typeof(Person), "p");            Expression ageExpr = Expression.Property(p, "Age");            Expression valueExpr = Expression.Constant(30);            Expression conditionExpr = Expression.GreaterThan(ageExpr, valueExpr);            Expression> whereExpr = Expression.Lambda>(conditionExpr, p);            IEnumerable resultSet = people.AsQueryable().Where(whereExpr);            // 输出查询结果            foreach (Person person in resultSet)            {                Console.WriteLine($"Name:{person.Name}, Age:{person.Age}");            }        }    }}

我们使用Expression.Parameter方法来创建一个参数p,指定Person类型,并指定其参数名称"p"。然后,我们以p为参数,使用Expression.Property(p, "Age")创建了一个表示参数对象的Age属性的MemberExpression。接着,我们使用Expression.Constant方法创建了一个值30的常量表达式valueExpr。我们使用Expression.GreaterThan方法将ageExprvalueExpr联合起来构建了一个大于30的条件表达式conditionExpr。最后,我们使用Expression.Lambda方法以p参数和conditionExpr表达式构建了一个Func类型的 lambda 表达式whereExpr。接着,我们使用了people.AsQueryable().Where方法将whereExpr表达式作为lambda参数传入,并执行查询。最后,我们遍历了resultSet输出了查询结果。

高级用法

在基本用法中,我们展示了如何使用表达式树来动态生成 lambda 表达式和 LINQ 查询语句。在实际开发中,还有一些更高级的用法可以充分地利用表达式树的能力,例如:

动态调用方法

在 C# 中,我们可以使用表达式树来动态地调用方法并获取方法的返回值。例如,我们可以动态地调用字符串的Contains方法:

using System;using System.Linq.Expressions;namespace ExpressionDemo{    internal class Program    {        static void Main(string[] args)        {            // 创建字符串参数表达式            ParameterExpression str = Expression.Parameter(typeof(string), "str");            // 获取 Contains() 方法            var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });            // 创建 Contains() 方法调用表达式            var call = Expression.Call(str, containsMethod, Expression.Constant("world"));            // 编译表达式并执行            var method = Expression.Lambda>(call, str).Compile();            Console.WriteLine(method("Hello, world!")); // 输出 True        }    }}

我们使用typeof(string).GetMethod("Contains", new[] { typeof(string) })获取string类型的Contains方法并传入new[] { typeof(string) },指定该方法需要一个string类型的参数。接着,我们创建了一个调用Contains方法的表达式call,即Contains(str, "world")。最后,我们使用LambdaCompile方法将表达式编译成可以直接执行的代码块并执行请求。

动态构造可调用对象

有时候,我们需要动态地构造一个可以调用的对象。例如,我们可以使用表达式树来创建一个可调用对象的实例,并将该实例作为参数传递给另一个函数。

using System;using System.Linq.Expressions;namespace ExpressionDemo{    interface ICalculator    {        double Add(double a, double b);    }    class AdditionCalculator : ICalculator    {        public double Add(double a, double b) => a + b;    }    internal class Program    {        static void Main(string[] args)        {            // 创建 AdditionCalculator 的实例            var constructor = Expression.New(typeof(AdditionCalculator).GetConstructor(new Type[0]));            var additionCalculatorExpr = Expression.Convert(constructor, typeof(ICalculator));            // 创建 Lambda 表达式,并调用 Add 方法            var a = Expression.Parameter(typeof(double), "a");            var b = Expression.Parameter(typeof(double), "b");            var add = Expression.Call(additionCalculatorExpr, typeof(ICalculator).GetMethod("Add"), a, b);            var expressionLambda = Expression.Lambda>(add, a, b);            var additionFunc = expressionLambda.Compile();            // 执行函数            Console.WriteLine(additionFunc(1.5, 2.5)); // 输出 4.0        }    }}

通过Expression.New方法创建AdditionCalculator对象的实例并转换为其接口类型ICalculator。接着,我们调用了ICalculatorAdd方法并将additionCalculatorExprab作为参数传递。然后,我们使用Lambda方法构建了一个Func委托类型,并调用Compile方法将其编译为可调用方法并执行请求。

总结

C# 表达式树是一个非常强大的工具,可以用于动态生成 lambda 表达式和 LINQ 查询,同时还可以用于动态调用方法、动态构造可调用对象和动态生成 C# 代码。在实际开发中,我们可以利用这些高级功能来优化代码,扩展应用的功能,提高应用的可维护性。

标签:

今日报丨涿鹿之战的故事300字_涿鹿之战的故事

新华网 2023-04-30 20:15:12

草莓舌的孩子一般是什么体质_草莓舌是什么原因造成的

新华网 2023-04-30 19:04:43

领略草原赛马速度与激情 300多名骑手理塘赛马称雄

新华网 2023-04-30 17:57:10

2.4亿!今年“五一”假期旅游人次将超过2019年同期

新华网 2023-04-30 16:48:42

为何有史学家说,明朝末年就算秦皇汉武来了,一样无法转危为安?|环球微头条

新华网 2023-04-30 15:13:21

黄鹤楼:今日停止售票

新华网 2023-04-30 13:54:38

世界通讯!双舰合壁!中国海军再赴苏丹港完成第二批中外公民撤离

新华网 2023-04-30 12:58:15

现实_关于现实介绍

新华网 2023-04-30 12:00:01

【全球独家】三星手机忘记密码怎么恢复出厂设置视频 三星手机恢复出厂设置在哪里

新华网 2023-04-30 11:07:01

解读尹锡悦美国会演讲提及长津湖战役

新华网 2023-04-30 10:19:41

2023国际消费季暨上海“五五购物节”在沪启动

新华网 2023-04-30 09:43:06

河南你早丨河南发布一批干部拟任职公示;河南2023年义务教育招生入学工作通知发布;开封火车站将暂时停办客运业务

新华网 2023-04-30 08:55:29

选手陈虹伊以总分58.81排名第22位成功晋级自由滑

新华网 2023-04-30 07:08:17

索尼游戏改编喜剧《烈火战车》预告片公布

新华网 2023-04-30 05:55:11

成都车站预计将迎来五一客流最高峰_天天热点评

新华网 2023-04-30 04:18:21
x 广告
x 广告

Copyright @  2015-2022 东方晚报网版权所有  备案号: 沪ICP备2020036824号-8   联系邮箱:562 66 29@qq.com