欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#表達(dá)式樹(shù)Expression基礎(chǔ)講解

 更新時(shí)間:2021年12月25日 11:30:29   作者:阿波Plus  
這篇文章介紹了C#表達(dá)式樹(shù)Expression和基本用法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

什么是表達(dá)式樹(shù)

表達(dá)式樹(shù)以樹(shù)形數(shù)據(jù)結(jié)構(gòu)表示代碼,其中每一個(gè)節(jié)點(diǎn)都是一種表達(dá)式,比如方法調(diào)用和 x < y 這樣的二元運(yùn)算等??梢詫?duì)表達(dá)式樹(shù)中的代碼進(jìn)行編輯和運(yùn)算。 這樣能夠動(dòng)態(tài)修改可執(zhí)行代碼、在不同數(shù)據(jù)庫(kù)中執(zhí)行 LINQ 查詢(xún)以及創(chuàng)建動(dòng)態(tài)查詢(xún)。 表達(dá)式樹(shù)還能用于動(dòng)態(tài)語(yǔ)言運(yùn)行時(shí) (DLR) 以提供動(dòng)態(tài)語(yǔ)言和 .NET 之間的互操作性,同時(shí)保證編譯器編寫(xiě)員能夠發(fā)射表達(dá)式樹(shù)而非 Microsoft 中間語(yǔ)言 (MSIL)。 這段話是來(lái)自官網(wǎng)( [表達(dá)式樹(shù) (C#) | Microsoft Docs](表達(dá)式樹(shù) (C#) | Microsoft Docs) )的定義。

在 C# 中,我們可以通過(guò) Expression 的方式來(lái)手動(dòng)創(chuàng)建表達(dá)式樹(shù),比如:

[HttpGet]
public IActionResult Expression()
{
    // 查詢(xún) 年齡Age 大于 18 的元素
    Expression<Func<User,bool>> expression1 = x => x.Age > 18; 
    return Ok();
}

那么,x.Age > 18 這一表達(dá)式,它的樹(shù)狀結(jié)構(gòu)是這樣的:

通過(guò) Visual Studio 自帶的查看變量或添加監(jiān)視的方式,我們可以發(fā)現(xiàn)其中 樹(shù)的根節(jié)點(diǎn)(NodeType)是 GreaterThan,左節(jié)點(diǎn)(Left)是 x.Age,右節(jié)點(diǎn)(Right)是 18。所以由此就可以大概畫(huà)出樹(shù)狀結(jié)構(gòu)。

最后,通過(guò)這種樹(shù)狀結(jié)構(gòu),C# 就可以幫我們將表達(dá)式編譯成具體的 SQL 執(zhí)行語(yǔ)句。

如果想更清晰的查看表達(dá)式樹(shù)的結(jié)構(gòu),可以 nuget 一個(gè)包( ExpressionTreeToString ),將表達(dá)式結(jié)構(gòu)轉(zhuǎn)換成字符串

PM> Install-Package ZSpitz.Util -Version 0.1.116
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 的區(qū)別

  • Expression 存儲(chǔ)了運(yùn)算邏輯,可以將其保存成抽象語(yǔ)法樹(shù)(AST),可以在運(yùn)行時(shí)動(dòng)態(tài)獲取運(yùn)算邏輯。
  • Func 只是存儲(chǔ)了結(jié)果,無(wú)法保存成語(yǔ)法樹(shù),也無(wú)法動(dòng)態(tài)獲取運(yùn)算邏輯。

所以,在 EFCore 中,使用表達(dá)式對(duì)數(shù)據(jù)庫(kù)數(shù)據(jù)進(jìn)行查詢(xún)中,我們應(yīng)該選擇 Expression 而不是 Func,因?yàn)槭褂昧?Func ,實(shí)際上并無(wú)法將 Func 中的表達(dá)式轉(zhuǎn)換成 SQL,而是在將所有數(shù)據(jù)加載到內(nèi)存后,在內(nèi)存中在過(guò)濾 Func 中的條件。

簡(jiǎn)單來(lái)說(shuō)就是,此時(shí)要篩選 User 表中年齡大于18的數(shù)據(jù),可以有這兩種寫(xiě)法

// 這種寫(xiě)法,實(shí)際生成的 SQL 語(yǔ)句, 大概是這樣的 SELECT * FROM User as T WHERE T.age > 18
Expression<Func<User,bool>> expression1 = x => x.Age > 18;
dbContext.User.Where(expression1).toList();

// 而這種, 生成的語(yǔ)句是這樣的 SELECT * FROM User, 然后將 User 表中所有數(shù)據(jù)加載到內(nèi)存中后, 在進(jìn)行 age > 18 的過(guò)濾
Func<User, bool> func1 = x => x.Age > 18;
dbContext.User.Where(func1).toList();

通過(guò)代碼創(chuàng)建表達(dá)式樹(shù)

  • ParameterExpression
  • BinaryExpression
  • MethodCallExpression
  • ConstantExpression

這些類(lèi)幾乎都沒(méi)有提供構(gòu)造方法,而且所有的屬性都幾乎只是只讀。因此我們一般不會(huì)直接創(chuàng)建這些類(lèi)的實(shí)例,而是調(diào)用 Expression 類(lèi)的 Parameter、MakeBinary、Call、Constant等靜態(tài)方法來(lái)生成,這些靜態(tài)方法我們一般稱(chēng)作創(chuàng)建表達(dá)式樹(shù)的工廠方法,而屬性則通過(guò)方法參數(shù)類(lèi)設(shè)置。

動(dòng)態(tài)將表達(dá)式:u => u.Age >= 18; 通過(guò)代碼構(gòu)建出來(lái)

一般構(gòu)建步驟:

  • 先創(chuàng)建 ParameterExpression
  • 接著由里到外逐步構(gòu)建
    • 先左節(jié)點(diǎn)(Left)
    • 后右節(jié)點(diǎn)(Right)
    • 接著B(niǎo)ody節(jié)點(diǎn)
  • 將其拼接成 Expression
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
    });
}

到此這篇關(guān)于C#表達(dá)式樹(shù)Expression基礎(chǔ)講解的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 圖形學(xué)之Unity渲染管線流程分析

    圖形學(xué)之Unity渲染管線流程分析

    這篇文章主要介紹了圖形學(xué)之Unity渲染管線流程的相關(guān)資料,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • C# Bitmap圖像處理(含增強(qiáng)對(duì)比度的三種方法)

    C# Bitmap圖像處理(含增強(qiáng)對(duì)比度的三種方法)

    本文主要介紹了C# Bitmap圖像處理(含增強(qiáng)對(duì)比度的三種方法),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • c#如何使用 XML 文檔功能

    c#如何使用 XML 文檔功能

    這篇文章主要介紹了c#如何使用 XML 文檔功能,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2020-10-10
  • C#?異步多線程入門(mén)到精通之Thread篇

    C#?異步多線程入門(mén)到精通之Thread篇

    Thread?是?1.0?時(shí)代的產(chǎn)物,當(dāng)時(shí)?C#?就考慮到了多線程,于是就設(shè)計(jì)了?Thread?。其實(shí)現(xiàn)在不推薦使用,除非在維護(hù)老的項(xiàng)目已經(jīng)用了的。Thread?也是比較雞肋的,有很多缺陷,但也并不是一無(wú)是處
    2021-11-11
  • 基于C#的電視臺(tái)節(jié)目表接口調(diào)用代碼

    基于C#的電視臺(tái)節(jié)目表接口調(diào)用代碼

    這篇文章主要介紹了基于C#的電視臺(tái)節(jié)目表接口調(diào)用代碼的相關(guān)資料,需要的朋友可以參考下
    2016-06-06
  • 解析c# yield關(guān)鍵字

    解析c# yield關(guān)鍵字

    這篇文章主要介紹了c# yield關(guān)鍵字的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-08-08
  • C#畫(huà)筆Pen繪制曲線的方法

    C#畫(huà)筆Pen繪制曲線的方法

    這篇文章主要介紹了C#畫(huà)筆Pen繪制曲線的方法,主要涉及C#畫(huà)筆中DrawCurve方法的使用技巧,需要的朋友可以參考下
    2015-06-06
  • 一篇文章說(shuō)通C#的屬性Attribute

    一篇文章說(shuō)通C#的屬性Attribute

    這篇文章主要給大家介紹了如何通過(guò)一篇文章說(shuō)通C#的屬性Attribute,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Unity3D使用鼠標(biāo)旋轉(zhuǎn)縮放平移視角

    Unity3D使用鼠標(biāo)旋轉(zhuǎn)縮放平移視角

    這篇文章主要為大家詳細(xì)介紹了Unity3D使用鼠標(biāo)旋轉(zhuǎn)縮放平移視角,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • 利用C#實(shí)現(xiàn)記事本的功能的示例代碼

    利用C#實(shí)現(xiàn)記事本的功能的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)簡(jiǎn)單的記事本的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12

最新評(píng)論