C# 表达式树是 .NET 框架中的一项强大的功能,我们可以利用表达式树来动态生成 lambda 表达式和 LINQ 查询语句,这极大的方便了我们动态构建数据查询和过滤的逻辑。本文将从基本用法和高级用法两个方面来介绍 C# 表达式树。
基本用法首先,我们需要了解Expression
类型,这个类型是所有表达式树节点的基类,表达式树常用的基本节点类型还有ConstantExpression
、ParameterExpression
、BinaryExpression
、LambdaExpression
等。下面是一个基本的例子:
(资料图片仅供参考)
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
,将a
与b
相加并返回。然后,我们使用 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 列表 Listpeople = 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
方法将ageExpr
和valueExpr
联合起来构建了一个大于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")
。最后,我们使用Lambda
和Compile
方法将表达式编译成可以直接执行的代码块并执行请求。
有时候,我们需要动态地构造一个可以调用的对象。例如,我们可以使用表达式树来创建一个可调用对象的实例,并将该实例作为参数传递给另一个函数。
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
。接着,我们调用了ICalculator
的Add
方法并将additionCalculatorExpr
、a
和b
作为参数传递。然后,我们使用Lambda
方法构建了一个Func
委托类型,并调用Compile
方法将其编译为可调用方法并执行请求。
C# 表达式树是一个非常强大的工具,可以用于动态生成 lambda 表达式和 LINQ 查询,同时还可以用于动态调用方法、动态构造可调用对象和动态生成 C# 代码。在实际开发中,我们可以利用这些高级功能来优化代码,扩展应用的功能,提高应用的可维护性。
Copyright @ 2015-2022 东方晚报网版权所有 备案号: 沪ICP备2020036824号-8 联系邮箱:562 66 29@qq.com