【More Effective C#】LINQ表达式与方法调用的映射
LINQ構建在兩個概念之上,一種查詢語言和一系列將查詢語言轉換成方法調用的實現.在編譯時,編譯器將LINQ表達式(LINQ?to?object)轉換成方法調用.
.Net基礎類庫提供了兩種擴展方法.System.Linq.Enumerable使用了IEnumerable<T>上擴展來實現,而System.Linq.Queryable則提供了類似的一系列IQueryable<T>上的擴展.兩者的轉換略為不同.前者在編譯時轉換成相應的擴展方法調用.而后者則能將LINQ表達式轉換成SQL查詢,并有SQL數據庫引擎執行.
從LINQ表達式到方法調用的轉換時一個復雜的迭代過程.編譯器在轉換時也有一個特定的順序.
例如
?int[]?someNumbers?=?{?0,?1,?2,?3,?4,?5,?6,?7,?8,?9?};
????????????var?answer?=?from?n?in?someNumbers
?????????????????????????where?n?<?5
?????????????????????????select?n;
最后將轉換成
int[]?someNumbers?=?{?0,?1,?2,?3,?4,?5,?6,?7,?8,?9?};
????????????var?answer?=someNumbers.Where(n=>n<5);
可以看到.在上面的轉換后.Select被優化去掉了.這就是一個退化選擇.不止是Where和Select.相應的LINQ表達式都會被轉換成相應的擴展方法..
編譯器的轉換
C#編譯器將把查詢和lambda表達式(Linq?to?object)轉換成靜態委托,實力委托和閉包.
int[]?someNumbers?=?{?0,?1,?2,?3,?4,?5,?6,?7,?8,?9?};
????????????var?answer?=?from?n?in?someNumbers
?????????????????????????select?n;
把上邊的代碼編譯.使用Refletor打開程序集.查看生成的相關代碼.
?int[]?someNumbers?=?new?int[]?{?0,?1,?2,?3,?4,?5,?6,?7,?8,?9?};
????if?(CS$<>9__CachedAnonymousMethodDelegate1?==?null)
????{
????????CS$<>9__CachedAnonymousMethodDelegate1?=?new?Func<int,?int>(null,?(IntPtr)?<Main>b__0);
????}
????IEnumerable<int>?answer?=?Enumerable.Select<int,?int>(someNumbers,?CS$<>9__CachedAnonymousMethodDelegate1);
可以看到.編譯器自動生成了一個委托.下面.使用更為直觀的代碼描述.生成的代碼大致如下:
?private?static?int?HiddenFuc(int?n)
????????{
????????????return?n?*?n;
????????}
????????private?static?Func<int,?int>?HiddenDelegateDefinition
?int[]?someNumbers?=?new?int[]?{?0,?1,?2,?3,?4,?5,?6,?7,?8,?9?};
????????????if?(HiddenDelegateDefinition?==?null)
????????????{
????????????????HiddenDelegateDefinition?=?new?Func<int,?int>(HiddenFuc);
????????????}
????????????IEnumerable<int>?anser?=?someNumbers.Select<int,?int>(HiddenDelegateDefinition);
可以看到.編譯器生成了一個靜態方法實現Select表達式.并且通過委托實現查詢.
實際上.上述的lambda表達式的主體部分并沒有訪問任何實例變量或是局部變量.什么是實例變量.什么又是局部變量.?
訪問實例變量的Lambe表達式
public?class?ModFilter
????{
????????private?readonly?int?modulus;
????????public?ModFilter(int?mod)
????????{
????????????modulus?=?mod;
????????}
????????public?IEnumerable<int>?FindValues(IEnumerable<int>?sequence)
????????{
????????????return?from?n?in?sequence
???????????????????where?n?%?modulus?==?0???//訪¤問實例變量
???????????????????select?n?*?n;
????????}
????}
編譯器將會為你生成一個實例方法,生成的代碼大致如下
?public?class?ModFilter
????{
????????private?readonly?int?modulus;
????????public?ModFilter(int?mod)
????????{
????????????modulus?=?mod;
????????}
????????private?bool?WhereClause(int?n)
????????{
????????????return?(n?%?modulus)?==?0;
????????}
????????private?static?int?SelectClause(int?n)
????????{
????????????return?n?*?n;
????????}
????????private?static?Func<int,?int>?SelectDelegate;
????????public?IEnumerable<int>?FindValues(IEnumerable<int>?sequence)
????????{
????????????if?(SelectDelegate?==?null)
????????????{
????????????????SelectDelegate?=?new?Func<int,?int>(SelectClause);
????????????}
????????????return?sequence.Where<int>(new?Func<int,?bool>(this.WhereClause)).Select<int,?int>(SelectClause);
????????}
}
Lambda表達式訪問實例變量
? 若是Lambda表達式中訪問了外部方法的實例變量.則編譯器將自動生成一個私有的嵌套類型.
public?class?ModFilterCloser
????{
????????private?readonly?int?modulus;
????????public?ModFilterCloser(int?mod)
????????{
????????????modulus?=?mod;
????????}
????????public?IEnumerable<int>?FindValues(IEnumerable<int>?sequence)
????????{
????????????int?numValues?=?0;
????????????return?from?n?in?sequence
???????????????????where?n?%?modulus?==?0
???????????????????select?n?*?n?/?++numValues;?//調用了方法外的局部變量numValues
????????}
????}
生成的代碼大致如下.
?public?class?ModFilterCloser
????{
????????private?sealed?class?Closure
????????{
????????????public?ModFilterCloser?outer;
????????????public?int?numValues;
????????????public?int?SelectClause(int?n)
????????????{
????????????????return?(n?*?n)?/?++this.numValues;
????????????}
????????}
????????private?readonly?int?modulus;
????????public?ModFilterCloser(int?mod)
????????{
????????????modulus?=?mod;
????????}
????????private?bool?WhereClause(int?n)
????????{
????????????return?(n?%?modulus)?==?0;
????????}
????????public?IEnumerable<int>?FindValues(IEnumerable<int>?sequence)
????????{
????????????Closure?c?=?new?Closure();
????????????c.outer?=?this;
????????????c.numValues?=?0;
????????????return?sequence.Where<int>(new?Func<int,bool>(this.WhereClause)).Select<int,int>(c.SelectClause));
????????}
????}
LINQ?to?Sql?的實現
最后.要注意到.以上的轉換實現都是在Linq?to?object中實現.即IEnumberale<T>中.而LINQ?to?SQL?的轉換.編譯后可以看到.并沒發生任何變化.那是因為.只有在遍歷迭代時,延遲執行.LINQ?to?SQL?Provider才將LINQ表達式轉換成SQL查詢.
轉載于:https://www.cnblogs.com/kongyiyun/archive/2010/10/15/1851866.html
總結
以上是生活随笔為你收集整理的【More Effective C#】LINQ表达式与方法调用的映射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript:prototype
- 下一篇: winfrom水晶报表的创建