服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#表达式树Expression基础讲解

C#表达式树Expression基础讲解

2022-12-14 12:05阿波Plus C#

这篇文章介绍了C#表达式树Expression和基本用法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

什么是表达式树

表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等。可以对表达式树中的代码进行编辑和运算。 这样能够动态修改可执行代码、在不同数据库中执行 LINQ 查询以及创建动态查询。 表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET 之间的互操作性,同时保证编译器编写员能够发射表达式树而非 Microsoft 中间语言 (MSIL)。 这段话是来自官网( [表达式树 (C#) | Microsoft Docs](表达式树 (C#) | Microsoft Docs) )的定义。

在 C# 中,我们可以通过 Expression 的方式来手动创建表达式树,比如:

?
1
2
3
4
5
6
7
[HttpGet]
public IActionResult Expression()
{
    // 查询 年龄Age 大于 18 的元素
    Expression<Func<User,bool>> expression1 = x => x.Age > 18;
    return Ok();
}

那么,x.Age > 18 这一表达式,它的树状结构是这样的:

C#表达式树Expression基础讲解

通过 Visual Studio 自带的查看变量或添加监视的方式,我们可以发现其中 树的根节点(NodeType)是 GreaterThan,左节点(Left)是 x.Age,右节点(Right)是 18。所以由此就可以大概画出树状结构。

C#表达式树Expression基础讲解

最后,通过这种树状结构,C# 就可以帮我们将表达式编译成具体的 SQL 执行语句。

如果想更清晰的查看表达式树的结构,可以 nuget 一个包( ExpressionTreeToString ),将表达式结构转换成字符串

?
1
PM> Install-Package ZSpitz.Util -Version 0.1.116
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Expression<Func<User, bool>> expression = u => u.Age >= 18;
var treeStr = expression.ToString("Object notation", "C#");
 
// 输出为下面字符串
var u = new ParameterExpression {
    Type = typeof(User),
    IsByRef = false,
    Name = "u"
};
 
new Expression<Func<User, bool>> {
    NodeType = ExpressionType.Lambda,
    Type = typeof(Func<User, bool>),
    Parameters = new ReadOnlyCollection<ParameterExpression> {
        u
    },
    Body = new BinaryExpression {
        NodeType = ExpressionType.GreaterThanOrEqual,
        Type = typeof(bool),
        Left = new MemberExpression {
            Type = typeof(int),
            Expression = u,
            Member = typeof(User).GetProperty("Age")
        },
        Right = new ConstantExpression {
            Type = typeof(int),
            Value = 18
        }
    },
    ReturnType = typeof(bool)
}

Expression 和 Func 的区别

  • Expression 存储了运算逻辑,可以将其保存成抽象语法树(AST),可以在运行时动态获取运算逻辑。
  • Func 只是存储了结果,无法保存成语法树,也无法动态获取运算逻辑。

所以,在 EFCore 中,使用表达式对数据库数据进行查询中,我们应该选择 Expression 而不是 Func,因为使用了 Func ,实际上并无法将 Func 中的表达式转换成 SQL,而是在将所有数据加载到内存后,在内存中在过滤 Func 中的条件。

简单来说就是,此时要筛选 User 表中年龄大于18的数据,可以有这两种写法

?
1
2
3
4
5
6
7
// 这种写法,实际生成的 SQL 语句, 大概是这样的 SELECT * FROM User as T WHERE T.age > 18
Expression<Func<User,bool>> expression1 = x => x.Age > 18;
dbContext.User.Where(expression1).toList();
 
// 而这种, 生成的语句是这样的 SELECT * FROM User, 然后将 User 表中所有数据加载到内存中后, 在进行 age > 18 的过滤
Func<User, bool> func1 = x => x.Age > 18;
dbContext.User.Where(func1).toList();

通过代码创建表达式树

  • ParameterExpression
  • BinaryExpression
  • MethodCallExpression
  • ConstantExpression

这些类几乎都没有提供构造方法,而且所有的属性都几乎只是只读。因此我们一般不会直接创建这些类的实例,而是调用 Expression 类的 Parameter、MakeBinary、Call、Constant等静态方法来生成,这些静态方法我们一般称作创建表达式树的工厂方法,而属性则通过方法参数类设置。

动态将表达式:u => u.Age >= 18; 通过代码构建出来

一般构建步骤:

  • 先创建 ParameterExpression
  • 接着由里到外逐步构建
    • 先左节点(Left)
    • 后右节点(Right)
    • 接着Body节点
  • 将其拼接成 Expression
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public IActionResult GetUserByManualExpression()
{
    ParameterExpression parameterExpression = Expression.Parameter(type:typeof(User), name: "u");
    ConstantExpression right = Expression.Constant(18);
    MemberExpression left = Expression.MakeMemberAccess(parameterExpression, member: typeof(User).GetProperty("Age"));
    BinaryExpression body = Expression.GreaterThanOrEqual(left, right);
 
    Expression<Func<User, bool>> expression = Expression.Lambda<Func<User, bool>>(body, parameters: parameterExpression);
 
    var data = _userService.GetUsers(expression);
 
    return Ok(new
    {
        code = 200,
        msg = "OK",
        data
    });
}

到此这篇关于C#表达式树Expression基础讲解的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://www.cnblogs.com/chenyanbo1024/p/15723922.html

延伸 · 阅读

精彩推荐
  • C#C#调用AForge实现摄像头录像的示例代码

    C#调用AForge实现摄像头录像的示例代码

    这篇文章主要介绍了C#调用AForge实现摄像头录像的示例代码,非常具有实用价值,需要的朋友可以参考下...

    asml11532022-01-22
  • C#.Net6开发winform程序使用依赖注入

    .Net6开发winform程序使用依赖注入

    本文详细讲解了.Net6开发winform程序使用依赖注入的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可...

    harrychinese5242022-12-13
  • C#C# 运算符 ?、??、?: 各种问号的用法和说明

    C# 运算符 ?、??、?: 各种问号的用法和说明

    本文介绍C#中三种常见的问号运算符的使用方法,简单讲解给大家,希望对大家有所帮助。...

    我不是高手9332021-11-18
  • C#C# 6.0的属性(Property)的语法与初始值详解

    C# 6.0的属性(Property)的语法与初始值详解

    下面小编就为大家带来一篇C# 6.0的属性(Property)的语法与初始值详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    C#教程网5882021-11-30
  • C#讲解C#面相对象编程中的类与对象的特性与概念

    讲解C#面相对象编程中的类与对象的特性与概念

    这篇文章主要介绍了C#面相对象编程中的类与对象的特性与概念,OOP面向对象语言相对C语言这样面相过程的语言来说具有类和对象以及方法这样的特性,需要...

    C#教程网10502021-11-09
  • C#C#中ManualResetEvent用法总结

    C#中ManualResetEvent用法总结

    这篇文章主要介绍了C#中ManualResetEvent用法总结,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...

    旷野风筝少年4222022-10-31
  • C#百度人脸识别之人脸识别FaceIdentify(签到考勤)

    百度人脸识别之人脸识别FaceIdentify(签到考勤)

    这篇文章主要为大家详细介绍了百度人脸识别之人脸识别FaceIdentify,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    杨小哥9652022-08-04
  • C#Unity3D实现控制摄像机移动

    Unity3D实现控制摄像机移动

    这篇文章主要为大家详细介绍了Unity3D实现控制摄像机移动 ,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    JayW就是我吖12192022-03-10