委託發展史 三

2022-04-06 15:33:06 字數 3464 閱讀 8705

通過c#2極大的簡化了委託的使用。如果僅僅是為了簡化事件的訂閱以及增強可讀性,這些技術確實已經足夠了。

但是,c#2中的委託仍然過於臃腫:一頁充滿匿名方法的**,讀起來真讓人難受,你也肯定不願意經常在乙個語句中放入多個匿名方法吧。

c#3可以說是乙個工業革命。

從許多方面lambda表示式都可以看做是c#2的匿名方法的一種演變。

匿名方法能做到的幾乎一切事情都可以用lambda表示式來完成,另外,幾乎所有情況下,lambda表示式都更易讀,更緊湊。

從最顯而易見的方面看,兩者並無多大區別--只是lambda支援許多簡化語法使他們在常規條件下顯得更簡練。

與匿名方法相似,lambda表示式有特殊的轉換規則:表示式的型別本身並非委託型別,但它可以通過多種方式隱式或顯式轉換成乙個委託例項。

匿名函式這個術語同時涵蓋了匿名方和lambda表示式--,在很多情況下,兩者可以使用相同的轉換規則。

慢慢來看這一場工業革命吧。。。

在.net3.5的system命名空間中,有5個泛型func委託型別,

func並無特別之處——只是他提供了一些好用的預定義泛型型別,在很多情況下能幫助我們處理問題。

每個委託簽名都獲取0~4個引數,其型別用型別引數來指定。最後乙個型別引數用作每種情況下的返回型別。

通俗講就是這個func是乙個有返回值委託型別。

看一下.net3.5所有func委託的簽名:

public delegate tresult func();

public delegate tresult func

(t arg);

public delegate tresult func

(t1 arg1,t2 arg2);

public delegate tresult func

(t1 arg1,t2 arg2,t3 arg3);

public delegate tresult func

(t1 arg1,t2 arg2, t3 arg3, t4 arg4);

例如,func等價於以下形式的委託型別。

public

delegate

int testdelegate(string arg1, double arg2);

當你想返回void時,也就是無返回值,可使用action<...>系列委託,其功能相似。

action在.net2.0中就有了,但其他都是.net 3.5新增的。如果4個引數還嫌不夠,.net 4將action與func家族擴充套件為擁有16個引數。

因此func擁有17個引數型別。

例如,我們需要獲取乙個stirng引數,並返回乙個int,所以我們將使用func。

funcreturnlength;

returnlength = delegate (string text) ;

console.writeline(returnlength(

"hello

"));

最後會輸出"5",預料之中。

注意上面的**,returnlength的宣告與賦值是分開的,否則一行可能放不下——除此之外,這樣還有利於對**的理解。所以,我們將它轉換成lambda表示式

lambda表示式最冗長的形式是:

(顯式型別的引數列表) =>
=>這個是c#3新增的,他告訴編譯器我們正在使用乙個lambda表示式。lambda表示式大多數時候都和乙個返回非void的委託型別配合使用——如果不反悔乙個結果,語法就不像現在這樣一目了然。

這個版本包含顯式引數,並將語句放到大括號中,他看起來和匿名方法非常相似。

funcreturnlength;

returnlength = (string text) => ;

console.writeline(returnlength(

"hello

"));

在閱讀lambda表示式時,可以將=>部分看成"goes to"。

匿名方法中控制返回語句的規則同樣適用與lambda表示式:不能從lambda表示式返回void型別;

如果有乙個非void的返回型別,那麼每個**路徑都必須返回乙個相容的值。

到目前為止,使用lambda表示式並沒有節省多大空間,或使**變得容易閱讀。

我們目前使用乙個完整的**塊來返回值,這樣可以靈活地處理多種情況——可以在**塊中放入多個語句,可以執行迴圈,可以從**塊中不同位置返回。。。等等

這和匿名方法是一樣的。

然而,大多數時候,都可以用乙個表示式來表示整個主體,該表示式是lambda結果。(意思就是,一條語句就可以解決的事)

這些情況下,可以指定那個表示式,不用大括號;不使用return語句,也不新增分號,格式隨即變成:

(顯式型別的引數列表) => 表示式
在我們的例子中,就變成了——

(string text) => text.length
現在已經開始變得簡單了,接著來考慮一下引數型別。編譯器已經知道func的例項獲取單個字串,所以只需命名那個引數就可以了。

感覺還是得分兩行來宣告跟賦值啊。。。

編譯器大多數時候都能猜出引數型別,不需要你顯示宣告他們。這些情況下,

還可以更加簡便些。

(隱式型別的引數列表) => 表示式
嗯,更加簡便了,lambda表示式也變成了這樣:

(text) => text.length
隱式型別的引數列表就是乙個以逗號分隔的名稱列表,沒有型別。但是隱式和顯式型別的引數不能混合匹配——要麼整個列表都是顯式型別,要麼都是隱式型別。

如果存在out 或 ref引數,那麼就只能是顯式型別了。

上面的lambda表示式已經相當簡短了,可以繼續簡化的地方不多了。

哎~這個圓括號看起來有點多餘啊。除去它!

如果lambda表示式只需要乙個引數,而且那個引數可以隱式指定型別,c#3就允許省略圓括號。這種lambda表示式是:

引數名 => 表示式
因此我們的lambda表示式最終形式是:

text => text.length
這樣的話如果一小段**中含有多個lambda,那麼拿掉引數列表的圓括號之後,對於可讀性來說是增強不少的。

還有如果願意,可以用圓括號將整個lambda表示式括起來。

在大多數情況下這種形式都是十分易讀的,例如之前的例子寫出來就是這樣:

funcreturnlength;

returnlength = text =>text.length;

console.writeline(returnlength(

"hello

"));

可能剛開始讀起來有點"彆扭",不過很快就習慣啦~

當你習慣了lambda表示式之後,你一定會感慨他們是多麼的簡潔,很難想象還可以使用更短,更清晰的方式老建立委託例項。

IT薪水發展史

1k 兄弟別做it了,不論你是什麼公司,國營的做it就是配角,那位兄弟願意一輩子做配角,非國營的嗎,看看做什麼別的合適,it不好混,趁早離開 1k 3k 初級階段,一般是剛進公司的,肯定非常缺錢,這時候動力足,也有時間,沒有男 女朋友拖累,象公司內部5k 6k的高手學習。什麼,沒有,什麼爛公司,你也...

記憶體發展史

記憶體 容量 指標 時期出現原因 simm記憶體 30pin 256kb 1982年至今 軟體程式和新一代80286硬體平台的出現 simm記憶體 72pin 512kb 2mb 1988 1990 pc迎來386和486時代,cpu向16bit發展 edo dram 4 16mb 電壓 5v 頻寬...

前端發展史

不知道什麼時候開始,前端開發已經到了不開乙個 watcher 就無法工作的地步了。不依賴 gulp babel webpack,還能優雅地寫 嗎?那我就帶你來回顧一下這一切是怎麼發生的。從哪開始說好呢?我們就從 前端打包 開始吧。前端打包 很久以前 也就五年左右吧,但是五年前端已經大變樣了 頁面的 ...