??? For,do… while,while ,foreach是大多數(shù)編程語言中常用的循環(huán)控制語句,在C#中查詢表達(dá)式也能實現(xiàn)同樣的效果。
??? 查詢表達(dá)式使得編程風(fēng)格從”命令式”變得更加的”聲明式”。查詢表達(dá)式定義想要的結(jié)果以及要達(dá)到該結(jié)果需要執(zhí)行的方法,而不是具體的如何實現(xiàn)。這里重點是查詢表達(dá)式,通過擴(kuò)展方法,查詢表達(dá)式使得能夠比命令式循環(huán)構(gòu)造更能夠清楚的表達(dá)意圖。
??? 下面的語句顯示了一個命令式風(fēng)格的填充一個數(shù)組并打印到控制臺上:
int
[] foo =
new int
[100];
for
(
int
num = 0; num < foo.Length; num++)
{
foo[num] = num * num;
}
foreach
(
int
i
in
foo)
{
Console
.WriteLine(i.ToString());
}
即使實現(xiàn)這么一小點功能,依然注重的是如何實現(xiàn)而不是怎樣實現(xiàn),將這段代碼改為查詢表達(dá)式能夠使得代碼更易讀和使用:
int
[] foo = (
from
n
in
Enumerable
.Range(0, 100)
select
n * n).ToArray();
第二個循環(huán)可以利用擴(kuò)展方法改寫為:
foo.ForAll(n =>
Console
.WriteLine(n));
或者更為簡潔的:
foo.ForAll(
Console
.WriteLine);
在.NET BCL中ForEach擴(kuò)展方法有針對List<T>的實現(xiàn)方法。我們可以添加一個針對IEnumerable<T>的ForAll擴(kuò)展方法實現(xiàn)如下:
public static class
Extensions
{
public static void
ForAll<T>(
this
IEnumerable
<T> sequence,
Action
<T> action)
{
foreach
(T item
in
sequence)
{
action(item);
}
}
}
? 可能看起來不起眼,只不過是一個擴(kuò)展方法而已,但是這能夠使得代碼能夠更多的重用,任何時候要對一個序列元素執(zhí)行操作,F(xiàn)orAll就能夠派上用場。
??? 以上問題可能看上去比較簡單,不足以看出使用查詢語法所帶來的好處,下面來看個復(fù)雜一點的。
很多操作需要嵌套的循環(huán)操作,假設(shè)需要產(chǎn)生一個從0到99的(X,Y)對,通常的做法是:
public static
IEnumerable
<
Tuple
<
Int32
,
Int32
>> ProduceIndices()
{
for
(
int
x = 0; x < 100; x++)
{
for
(
int
y = 0; y < 100; y++)
{
yield return
Tuple
.Create(x, y);
}
}
}
或者改為查詢表達(dá)式:
public static
IEnumerable
<
Tuple
<
Int32
,
Int32
>> ProduceIndices()
{
return from
x
in
Enumerable
.Range(1, 100)
from
y
in
Enumerable
.Range(1, 100)
select
Tuple
.Create(x, y);
}
兩者看起來差不多,但是隨著問題的復(fù)雜,查詢表達(dá)式仍然能夠保持簡潔。現(xiàn)在將問題改為:只產(chǎn)生x和y相加小于100的點對,比較兩者的實現(xiàn):
public static
IEnumerable
<
Tuple
<
Int32
,
Int32
>> ProduceIndices2()
{
for
(
int
x = 0; x < 100; x++)
{
for
(
int
y = 0; y < 100; y++)
{
if
(x+y<100)
yield return
Tuple
.Create(x, y);
}
}
}
public static
IEnumerable
<
Tuple
<
Int32
,
Int32
>> ProduceIndices2()
{
return from
x
in
Enumerable
.Range(1, 100)
from
y
in
Enumerable
.Range(1, 100)
where
x+y<100
select
Tuple
.Create(x, y);
}
?
差距仍不明顯,但是命令式語句開始隱藏我們想要的意圖。再將問題變得復(fù)雜一些。現(xiàn)在,我們需要將返回的點按照距離原點位置的距離降序排列。
public static
IEnumerable
<
Tuple
<
Int32
,
Int32
>> ProduceIndices3()
{
var
storage =
new
List
<
Tuple
<
int
,
int
>>();
for
(
int
x = 0; x < 100; x++)
{
for
(
int
y = 0; y < 100; y++)
{
if
(x+y<100)
storage.Add(
Tuple
.Create(x, y));
}
}
storage.Sort((point1,point2)=>
(point2.Item1*point2.Item1+point2.Item2*point2.Item2).CompareTo
(point1.Item1 * point1.Item1 + point1.Item2 * point1.Item2)
);
return
storage;
}
public static
IEnumerable
<
Tuple
<
Int32
,
Int32
>> ProduceIndices3()
{
return from
x
in
Enumerable
.Range(1, 100)
from
y
in
Enumerable
.Range(1, 100)
where
x + y < 100
orderby
(x * x + y * y)
descending select
Tuple
.Create(x, y);
}
?? 現(xiàn)在,差距開始出現(xiàn)了,命令式的風(fēng)格時的代碼難以理解,如果不認(rèn)真的看,很難一下子明白比較函數(shù)后面一堆東西返回的是什么。如果沒有注釋的話,這段命令式代碼比較難懂。命令式風(fēng)格的代碼過多的強調(diào)了代碼執(zhí)行的過程,很容易在這復(fù)雜的過程中迷失我們最初想要達(dá)到的目的。
?? 查詢表達(dá)式比循環(huán)控制結(jié)構(gòu)更好的一點是:查詢表示式能夠更好的組合,他能夠?qū)⑺惴ńM織在一個很小的精簡的片段內(nèi)來執(zhí)行一系列的操作。查詢的惰性執(zhí)行模型也使得開發(fā)者能夠在一個循環(huán)類執(zhí)行一系列的操作。而查詢表達(dá)式則不能做到這一點。你必須存儲每一次循環(huán)的結(jié)果,然后構(gòu)造新的循環(huán)操作來執(zhí)行上一次的操作結(jié)果。
?? 最后一個例子演示了如何工作。操作組合了過濾(where子句),排序(orderby 子句)以及投影(select語句),所有這些操作在一次遍歷操作中完成。而命令式版本的方法需要創(chuàng)建一個零時的存儲對象storage,然后對這個對象分別執(zhí)行一些列操作。
每一個查詢表達(dá)式有一個對應(yīng)的方法調(diào)用是的表達(dá)式,有時候,查詢表達(dá)式更自然有時候方法調(diào)用是的表達(dá)式更自然。顯然在上面的例子中,查詢表達(dá)式版本更易讀,下面是方法調(diào)用的版本:
public static
IEnumerable
<
Tuple
<
Int32
,
Int32
>> ProduceIndices3()
{
return
Enumerable.Range(1, 100).
SelectMany(x => Enumerable.Range(1, 100),
(x, y) =>
Tuple
.Create(x, y)).Where(pt => pt.Item1 + pt.Item2 < 100).
OrderByDescending(pt => pt.Item1 * pt.Item1 + pt.Item2 * pt.Item2);
}
?? 在這個例子中,查詢表達(dá)式可能比方法表達(dá)式更易讀,但其他例子可能不同。有些方法表達(dá)式并沒有對應(yīng)的查詢表達(dá)式。一些方法,如Take,TakeWhile,Skip,SkipWhile,Min,以及Max在一些情況下需要使用方法表達(dá)式。
?? 有些人可能會人會查詢表達(dá)式在執(zhí)行速度上比循環(huán)執(zhí)慢,這一點要看具體的情況。有時候清晰的代碼可能比速度更重要。在改進(jìn)程序算法之前,可以考慮LINQ的并行擴(kuò)展庫PLINQ,可以使用.AsParallel()來使的查詢操作能夠并行執(zhí)行。
?? C#最開始是一種命令式編程語言,你能夠使用之前最熟悉的方法去編寫代碼。但是這些傳統(tǒng)的方法可能不是最好的。當(dāng)你發(fā)現(xiàn)需要使用循環(huán)結(jié)構(gòu)去執(zhí)行某種操作的時候,試試能夠?qū)⑺膶憺椴樵儽磉_(dá)式的方式,如果查詢表達(dá)式不起作用,試試方法表達(dá)式,在大多數(shù)情況下,你會發(fā)現(xiàn)使用查詢表達(dá)式或者方法表達(dá)式會比使用傳統(tǒng)的循環(huán)式的命令式結(jié)構(gòu)能使得代碼變得更加簡潔和清晰。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

