關於Expression表示式樹的拼接

2022-01-16 14:51:32 字數 3246 閱讀 4012

最近在做專案中遇到乙個問題,需求是這樣的:

我要對已經存在的使用者進行檢索,可以根據使用者的id 或者使用者名稱其中的一部分字元來檢索出來,這樣就出現了三種情況 只有id,只有使用者名稱中一部字元,或者全部都有.

我們用的mvc+ef5.0的框架,在bll層進行查詢的 時候需要構建lambda表示式來作為查詢條件,但是,我們怎麼來構建lambda來確定查詢的條件呢?我們知道express>這樣的乙個引數可以是lambda表示式,但是這裡的按條件拼接式不能使用委託鏈的形式的.當然還有一種解決辦法,我把所有查詢條件都寫好,然後根據傳過來的id 或者使用者名稱 來判斷確定使用哪個..這樣的判斷邏輯混亂,**冗長,我們就想找乙個可以動態拼接查詢條件的方法.

即按照id 或者使用者名稱是否存在動態的來拼接查詢條件.

首先我們需要知道,表示式構成部分,表示式是有兩部分構成,parameter和body,第乙個是引數,第二個是表示式體,表示式體是二進位制的位運算,也就是 比如(left&right)而left和right要返回的值必須是基本型別的值,也就是可以參與位運算的值.例如(a,b)=>()這個lambda表示式中,ab是引數,括號後面中是表示式體這裡面返回的值只能是基本型別.我們要構建乙個表示式樹,主要就是構建這個表示式體,那麼這個表示式體是乙個什麼樣的型別呢 ?binaryexpression型別,我們只需要構造這個型別,然後通過expression.and(left,right)或者expression.or()這兩個方法來構造即可. 這個兩個方法返回值就是binaryexpression的型別物件.然後我們在用expression.lambda>(binaryexpression,parameter)這個方法將這個表示式樹轉化為lambda的表示式.這就是這個問題的 解決思路,來看看我們是怎麼來實現的.

首先我們定義了乙個表示式變數.

expression> where;

然後我們開始進行labmda的構造

接下來,我們來構造引數和必要條件,也是就lambda中的c=>()中的c

parameterexpression param = expression.parameter(typeof(userinfo), "c");//c=>

//c=>c.isdelete==false這裡需要不被刪除的條件

memberexpression left1 = expression.property(param, typeof(userinfo).getproperty("isdelete"));構建c.isdelete

constantexpression right1 = expression.constant(false);//構建乙個常量 false

binaryexpression be = expression.equal(left1, right1);構建//c=>c.isdelete==false 就是現在這個be了

下面 我們需要根據我們的條件 也就是id和使用者名稱字串來繼續拼接這個表示式

首先我們來拼接c.userid==sid

if (!string.isnullorempty(request["sid"]))

int sid = int.parse(request["sid"]);

//根據引數的屬性構造左表示式c.userid

memberexpression left2 = expression.property(param, typeof(userinfo).getproperty("userid"));

//構造右表示式sid

constantexpression right2 = expression.constant(sid);

//進行合併:cuserid==sid

binaryexpression where2 = expression.equal(left2, right2);

be = expression.and(be, where2);

現在我們來拼接第二個條件

前面我們已經說過,表示式體需要返回的是可以做二進位制運算的型別,但是這是個值型別字串,該怎麼辦呢?

在參考了msdn中的expression方法中,發現有這樣的乙個方法.expression.call().

然後看了示例這個

究竟是用來幹嘛的??

我們可以用這個call』方法 ,來呼叫乙個型別 中的乙個方法,然後產生乙個methodcallexpression型別的返回值,這樣,我們來呼叫string. contains方法不就可以完成我們想要的表示式了麼?

且看下面的 **

if (!string.isnullorempty(request["sname"]))

string sname = request["sname"];

memberexpression left3 = expression.property(param, typeof(userinfo).getproperty("username"));//這裡構造c.username這個屬性表示式.

constantexpression right3 = expression.constant(sname);//這裡構造sname這個常量表示式

methodcallexpression where3 = expression.call(left3, typeof(string).getmethod("contains"), right3);這裡我們用call這個方法完成/c.username.contains(sname)這個lambda這個表示式的實現.

be = expression.and(be, where3);//拼接剛才的be表示式,

where = expression.lambda>(be, param);//生成最後需要的帶引數的表示式樹.

這樣我們的表示式樹拼接就完成了.

至於執行結果就不為大家貼圖了,可以執行和lambda的結果一樣.可以完成兩個條件的查詢.

1

public

class wherehelper2

3where t:class45

2425

public expressionbool>>getexpression()

2627

3233

public

void equal(string propertyname,object

value)

3435

4647

public

void contains(string propertyname,string

value)

4849

6061 }

當然,這個幫助類功能有限,如果有需要者,大家可以自己進行擴充.

解析Expression 表示式

前言 時光荏苒,2020年不覺中已成過去。2021剛剛開頭,新的開始本應意氣風發 本應有會當凌絕頂豪情壯志,再不濟也該 鴻圖霸業談笑間 且不管一入江湖是不是歲月摧的灑脫。很不幸,有些事情就是會突入其來,搞得你觸不及防,什麼心情都沒有。但是我居然還是寫下了這篇部落格。嗯,總算是有地方表達以我糟糕心情了...

關於Expression表示式樹的拼接

最近在做專案中遇到乙個問題,需求是這樣的 我要對已經存在的使用者進行檢索,可以根據使用者的id 或者使用者名稱其中的一部分字元來檢索出來,這樣就出現了三種情況 只有id,只有使用者名稱中一部字元,或者全部都有.我們用的mvc ef5.0的框架,在bll層進行查詢的 時候需要構建lambda表示式來作...

LINQ 表示式樹 Expression

在 linq to objects 中,擴充套件方法需要將乙個委託型別作為引數,這樣就可以將 表示式賦予引數。達式也可以賦予expression型別的引數。expression型別指定,來自於 表示式的表示式樹儲存在程式集中。這樣,就可以在執行期間分析表示式,並進行優化,以便於查詢資料來源。下面看看...