手工把LINQ轉成表示式(二) 準備工作

2021-05-27 11:08:43 字數 3792 閱讀 1815

先來看一句簡單的linq語句:

from item in source

select item

這裡如果寫成方法呼叫的話就是

source.select(item => item)

這意味著in後面的是作為方法呼叫的發起方(invoker) ,from是定義表示式引數,select才是真正的方法本身。

再來看個多語句的例子:

from a in a

where a != null

select a

不考慮優化的情況下寫成方法應該是

a.where(a => a != null).select(a => a)

也就是說可以認為前一句的輸出是後一句的輸入並且後一句還需要用到前一句的引數別名,在解析的時候需要一種機制能滿足這種要求,為了簡化處理不再採用遞迴方式分析,而是用了這麼乙個結構儲存解析linq時所有要用到的上下文場景:

internal class linqcontext

public string name

public expression self

private parameterexpression nextparameter;

public parameterexpression nextparameter

set}

private bool isfirst = false;

public bool isfirst

set

}}

parameter是當前的輸入引數,name代表引數名,self是當前語句的表示式,nextparameter是表示為下一句linq的輸入引數,isfirst標誌位表示是否是第乙個from語句(在介紹from時詳細說)。

這裡順便說一下,grammar又更新了,這次把所有賦值運算子全部移出二元運算子,目前的解析器暫時不支援帶賦值運算子的表示式解析。

有了這個結構我們就可以輕鬆把一句linq中的每個操作語句的上下文給儲存下來便於轉換了:

private

stack

_linqvariables;

這裡用了棧來儲存linq語句的上下文,實際實現下來感覺也並非必要,不過用棧的話可以逆推整個操作過程,對**除錯還是有點幫助的。

先通過grammar對linq語句解析後得到的是每一句linq的陣列,所以轉換入口就這麼寫了:

private expression processlinq(parsetreenode expnode)

return linq;

}

可以注意到,其實最後一句linq被轉換後返回的才是完整的表示式,其餘中間產生的表示式都入棧了返回值直接被忽略,這裡用遞迴的話可以節省那個棧但是除錯起來就麻煩了。

linq語句對應的方法定義為:

#region extensionmethods

extensionmethods["select"] = typeof(queryable).getextensionmethod("select", typeof(iqueryable<>), typeof(expression<>).makegenerictype(typeof(func<,>)));

extensionmethods["let"] = extensionmethods["select"];

extensionmethods["from"] = typeof(queryable).getextensionmethod("selectmany", typeof(iqueryable<>), typeof(expression<>).makegenerictype(typeof(func<,>)), typeof(expression<>).makegenerictype(typeof(func<,,>)));

extensionmethods["group"] = typeof(queryable).getextensionmethod("groupby", typeof(iqueryable<>), typeof(expression<>).makegenerictype(typeof(func<,>)));

extensionmethods["join"] = typeof(queryable).getextensionmethod("join", typeof(iqueryable<>), typeof(ienumerable<>), typeof(expression<>).makegenerictype(typeof(func<,>)), typeof(expression<>).makegenerictype(typeof(func<,>)), typeof(expression<>).makegenerictype(typeof(func<,,>)));

extensionmethods["groupjoin"] = typeof(queryable).getextensionmethod("groupjoin", typeof(iqueryable<>), typeof(ienumerable<>), typeof(expression<>).makegenerictype(typeof(func<,>)), typeof(expression<>).makegenerictype(typeof(func<,>)), typeof(expression<>).makegenerictype(typeof(func<,,>)));

extensionmethods["orderby"] = typeof(queryable).getextensionmethod("orderby", typeof(iqueryable<>), typeof(expression<>).makegenerictype(typeof(func<,>)));

extensionmethods["orderbydescending"] = typeof(queryable).getextensionmethod("orderbydescending", typeof(iqueryable<>), typeof(expression<>).makegenerictype(typeof(func<,>)));

extensionmethods["thenby"] = typeof(queryable).getextensionmethod("thenby", typeof(iorderedqueryable<>), typeof(expression<>).makegenerictype(typeof(func<,>)));

extensionmethods["thenbydescending"] = typeof(queryable).getextensionmethod("thenbydescending", typeof(iorderedqueryable<>), typeof(expression<>).makegenerictype(typeof(func<,>)));

extensionmethods["where"] = typeof(queryable).getextensionmethod("where", typeof(iqueryable<>), typeof(expression<>).makegenerictype(typeof(func<,>)));

extensionmethods["defaultifempty"] = typeof(enumerable).getextensionmethod("defaultifempty", typeof(ienumerable<>));

#endregion

這裡只把defaultifempty這個擴充套件單獨拿出來是為了支援left join語句,其他擴充套件方法就先不支援了。

在接下來的分析過程中,都是通過模仿c#編譯linq產生的表示式來生成我們自己的表示式的,並且忽略了優化。

linq表示式對比lambda表示式

什麼是linq表示式?什麼是lambda表示式?前一段時間用到這個只是,在網上也沒找到比較簡單明瞭的方法,今天就整理了一下相關知識,有空了再仔細研究研究 public program ling表示式 var stus1 from s in allstudent where s.name 王二 sel...

初識Linq表示式

由於近期做專案涉及到linq表示式,正好來學習一下。linq languageintegrated query 語言整合查詢,是一組用於 c 和visual basic語言的擴充套件。它允許編寫c 或者 visual basic 以查詢資料庫相同的方式操作記憶體資料。約束linq查詢表示式必須以fr...

Linq表示式開竅

static iqueryablegetpagelist expressionbool wherelambda,expression orderlambda,int pagesize,int pageindex where t class 上面值的返回型別是iqueryable,為什麼是這個型別呢?...