在開始今天的內容之前,我現在這回答楊裕欣同學的一個問題。我在昨天的文章中說過一個很核心的問題,linq其實有2套東西,用於處理本機資料源的IEnumerable<T>和處理遠端資料源的IQueryable<T>。然後本機資料源可以直接代入方法的邏輯進行處理,而遠端資料源必須把方法的邏輯變成運算式樹狀架構,再把運算式樹狀架構中相應的元素剝離出來,變成遠端資料源可以識別的邏輯進行處理,遠端資料源要這麼做是因為沒有了.net運行時這個內容相關的支援,所以無法識別.net中的方法的邏輯。
所以由此,就引出了楊裕欣同學的兩個問題:
a.比如對於IEnumerable<Customer> customers;
Customer類有個屬性:IList<String> Addresses;
var q = customers.Where(c => c.Addresses.Contain("xxxx"))
是否ok
b.如果把customers類型用AsQueryable函數轉成IQueryable<Customer> 又怎麼樣。。。
先回答問題a.肯定可以,因為本機資料源,有.net運行時的支援,可以直接把Contain方法的邏輯代入進行篩選
再來回答問題b.也可以,雖然AsQueryable使處理資料來源的方式變成了處理遠端資料源的方式,但同樣可以。為什嗎?ok,在回答為什麼之前,我們先來看看什麼情況下不行:
所謂IQueryable這套東西無法處理的,實際就是無法變成運算式樹狀架構的,根據msdn的資料:
http://msdn.microsoft.com/zh-cn/library/bb397687.aspx
無法變成運算式樹狀架構的典型情況有兩種,一種是用了.net中的方法
() => SomeMethod()
一種用了lamabda語句:
Lambda 語句與 Lambda 運算式類似,只是語句括在大括弧中: (input parameters) => {statement;}
Lambda 語句的主體可以包含任意數量的語句;但是,實際上通常不會多於兩個或三個語句。
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
總結起來,這兩種情況無法變成運算式樹狀架構都是因為調用了.net中的方法。所以楊裕欣同學的問題就很好理解了——Contain不是也是.net中的方法嗎?為什麼用了Contain方法就可以變成運算式樹狀架構,調其他很多方法就不行呢?
ok,這就引出了一個我們今天一定要講清楚的一個概念——Provider。
我們再來分析一下產生運算式樹狀架構的這個過程,IQueryable中式靠什麼把我們運算式(類似item => item.Length>3)中的基本邏輯解析成運算式樹狀架構的?
答案是——Provider,可以參考下msdn的資料:
http://msdn.microsoft.com/zh-cn/library/bb882636.aspx
現在問題就衍變成了為什麼有的方法Provider可以解析有的卻不能,我們能否找出Provider可以解析的方法的一個充要條件?
要回答這個問題,我們先回答另一個問題:Linq是用來做什麼的?Linq是用來查詢關係型資料來源的,這方面內容的詳情請參考這篇文章http://www.cnblogs.com/Ivony/archive/2008/08/28/1278643.html
簡而言之,Linq能處理的IEnumerable<T>,sql,xml都是關係型資料來源,而contain是定義在IEnumerable上的方法,相當於對關係的一種邏輯,所以Provider可以把它解析成運算式樹狀架構,再直接點,當IEnumerable<T>中的資料來源可以表示成一個關係時,它的方法就可以被解析成運算式樹狀架構。對於關係這個概念,非常推薦大家參考上面連結的Ivony的那篇文章,非常贊。
接下來,我們來講今天剩下的一個重要的內容:Lambda運算式。
我們先看一個普通的Lambda運算式:(x, y) => x == y。
我們先來回答一個問題:Lambda運算式本質是什嗎?
lambda 運算式是一種無名函數,用於計算並返回單個值。lambda 運算式可在委託類型有效任何地方使用。
請大家注意:只有可以表示為關係的Lambda運算式才能變成運算式樹狀架構
(x, y) => x == y 元素和元素的關係
x => x.Length>4 元素和屬性的關係
注意:沒有元素和方法的關係,要是調用了自訂的方法是無法產生合法的運算式樹狀架構的。
或者我們這麼理解:構成關係的集合必須是狀態的集合。
最後再強調下:Lambda運算式就是匿名方法,能變成運算式樹狀架構的Lamabda運算式是有限制的,Lambda語句無法變成運算式樹狀架構。
說下下一篇的預告:Lambda運算式樹狀架構。
話說這個系列已經寫了3篇了,這個系列不是講應用,主要想跟大家一起探討下Linq中一些原理和理論。希望目前的這幾篇文章能幫大家把以下知識點串起來:迭代器,IEnumerable,ICollection,IList之間的繼承關係,擴充方法,var,匿名函數,運算式,運算式樹狀架構,provider,linq中的2套東西(IEnumerable<T>和IQueryable<T>),關係。
最後的最後連結下楊裕欣童鞋的blog:http://www.cnblogs.com/yayx/