C#高階-委托和時(shí)間及l(fā)amda表達(dá)式

委托Delegate

????C#中的Delegate對(duì)應(yīng)于C中的指針,但是又有所不同C中的指針既可以指向方法,又可以指向變量,并且可以進(jìn)行類型轉(zhuǎn)換计济,

C中的指針實(shí)際上就是內(nèi)存地址變量,他是可以直接操作內(nèi)存的,通過內(nèi)存地址直接訪問變量排苍,直接調(diào)用方法沦寂。

????而C#中的Delegate是強(qiáng)類型的,也就是說在聲明委托時(shí)就已經(jīng)指定了該變量只能指向具有特定參數(shù)淘衙,以及返回值的方法凑队。

???使用delegate就可以直接建立任何名稱的委托類型,當(dāng)進(jìn)行系統(tǒng)編譯時(shí)幔翰,系統(tǒng)就會(huì)自動(dòng)生成此類型。您可以使用delegate void MyDelegate()

方式建立一個(gè)委托類西壮,并使用ILDASM.exe觀察其成員遗增。由ILDASM.exe 中可以看到,它繼承了System.MulticastDelegate類款青,

并自動(dòng)生成BeginInvoke做修、EndInvoke、Invoke 等三個(gè)常用方法抡草。

Invoke 方法是用于同步調(diào)用委托對(duì)象的對(duì)應(yīng)方法饰及,而BeginInvoke、EndInvoke是用于以異步方式調(diào)用對(duì)應(yīng)方法的康震。

public class MyDelegate:MulticastDelegate

?????{

?????????//同步調(diào)用委托方法

?????????public virtual void Invoke();

?????????//異步調(diào)用委托方法

?????????public virtual IAsyncResult BeginInvoke(AsyncCallback callback,object state);

?????????public virtual void EndInvoke(IAsyncResult result);

?????}

MulticastDelegate是System.Delegate的子類燎含,它是一個(gè)特殊類,編譯器和其他工具可以從此類派生腿短,但是自定義類不能顯式地從此類進(jìn)行派生屏箍。它支持多路廣播委托,并擁有一個(gè)帶有鏈接的委托列表橘忱,在調(diào)用多路廣播委托時(shí)赴魁,系統(tǒng)將按照調(diào)用列表中的委托出現(xiàn)順序來同步調(diào)用這些委托。

MulticastDelegate具有兩個(gè)常用屬性:Method钝诚、Target颖御。其中Method 用于獲取委托所表示的方法Target 用于獲取當(dāng)前調(diào)用的類實(shí)例。

委托的使用

當(dāng)建立委托對(duì)象時(shí)凝颇,委托的參數(shù)類型必須與委托方法相對(duì)應(yīng)潘拱。只要向建立委托對(duì)象的構(gòu)造函數(shù)中輸入方法名稱example.Method疹鳄,委托就會(huì)直接綁定此方法。使用myDelegate.Invoke(string message)泽铛,就能顯式調(diào)用委托方法尚辑。但在實(shí)際的操作中,我們無須用到 Invoke 方法盔腔,而只要直接使用myDelegate(string message)杠茬,就能調(diào)用委托方法。

無返回值的委托

class Program

????{

????????delegate void MyDelegate(string message);

????????public class Example

????????{

????????????public void Method(string message)

????????????{

????????????????MessageBox.Show(message);

????????????}

????????}

????????static void Main(string[] args)

????????{

????????????Example example=new Example();

????????????MyDelegate myDelegate=new MyDelegate(example.Method);

????????????myDelegate("Hello World");


????????}

????}

有返回值的委托

class Program

????{

????????delegate string MyDelegate(string message);

????????public class Example

????????{

????????????public string Method(string name)

????????????{

????????????????return "Hello " + name;

????????????}

????????}

????????static void Main(string[] args)

????????{

????????????Example example=new Example();

????????????//綁定委托方法

????????????MyDelegate myDelegate=new MyDelegate(example.Method);

????????????//調(diào)用委托弛随,獲取返回值

????????????string message = myDelegate("Leslie");

????????????Console.WriteLine(message);


????????}

????}

多路廣播委托

delegate double MyDelegate(double message);

????????public class Price

????????{

????????????public double Ordinary(double price)

????????????{

????????????????double price1 = 0.95 * price;

????????????????Console.WriteLine("Ordinary Price : "+price1);

????????????????return price1;

????????????}

????????????public double Favourable(double price)

????????????{

????????????????double price1 = 0.85 * price;

????????????????Console.WriteLine("Favourable Price : " + price1);

????????????????return price1;

????????????}

????????????static void Main(string[] args)

????????????{

????????????????Price price = new Price();

????????????????//綁定Ordinary方法

????????????????MyDelegate myDelegate = new MyDelegate(price.Ordinary);

????????????????//綁定Favourable方法

????????????????myDelegate += new MyDelegate(price.Favourable);

????????????????//調(diào)用委托

????????????????Console.WriteLine("Current Price : " + myDelegate(100));


????????????}

????????}

泛型委托

public class Worker???{???????int wages;???????public int Wages???????{???????????get { return wages; }???????????set { wages = value; }???????}???}???public class Manager : Worker???{ }???class Program???{???????public delegate void Handler(T obj);???????public static void GetWorkerWages(Worker worker)???????{???????????Console.WriteLine("Worker's total wages is " + worker.Wages);???????}???????public static void GetManagerWages(Manager manager)???????{???????????Console.WriteLine("Manager's total wages is " + manager.Wages);???????}???????static void Main(string[] args)???????{???????????HandlerworkerHander = new Handler(GetWorkerWages);???????????Worker worker = new Worker();???????????worker.Wages = 3000;???????????workerHander(worker);???????????HandlermanagerHandler = new Handler(GetManagerWages);

???????????Manager manager = new Manager();

???????????manager.Wages = 4500;

???????????managerHandler(manager);

???????}

???}

事件

產(chǎn)生原因

事件是特殊的委托瓢喉,他為委托提供了封裝性,一方面允許從類的外部增加舀透,刪除綁定方法栓票,另一方面又不允許從類的外部來觸發(fā)委托所綁定了方法。

public delegate double PriceHandler();

????public class PriceManager

????{

????????public PriceHandler GetPriceHandler;

????????//委托處理愕够,當(dāng)價(jià)格高于100元按8.8折計(jì)算走贪,其他按原價(jià)計(jì)算

????????public double GetPrice()

????????{

????????????if (GetPriceHandler.GetInvocationList().Count() > 0)

????????????{

????????????????if (GetPriceHandler() > 100)

????????????????????return GetPriceHandler()*0.88;

????????????????else

????????????????????return GetPriceHandler();

????????????}

????????????return -1;

????????}

????}

????class Program

????{

????????static void Main(string[] args)

????????{

????????????PriceManager priceManager = new PriceManager();


????????????//調(diào)用priceManager的GetPrice方法獲取價(jià)格

????????????//直接調(diào)用委托的Invoke獲取價(jià)格,兩者進(jìn)行比較

????????????priceManager.GetPriceHandler = new PriceHandler(ComputerPrice);

????????????Console.WriteLine(string.Format("GetPrice\n ?Computer's price is {0}!",

????????????????priceManager.GetPrice()));

????????????Console.WriteLine(string.Format("Invoke\n ?Computer's price is {0}!",

????????????????priceManager.GetPriceHandler.Invoke()));


????????????Console.WriteLine();


????????????priceManager.GetPriceHandler = new PriceHandler(BookPrice);

????????????Console.WriteLine(string.Format("GetPrice\n ?Book's price is {0}!",

????????????????priceManager.GetPrice()));

????????????Console.WriteLine(string.Format("Invoke\n ?Book's price is {0}!" ,

????????????????priceManager.GetPriceHandler.Invoke()));


????????????Console.ReadKey();

????????}

????????//書本價(jià)格為98元

????????public static double BookPrice()

????????{

????????????return 98.0;

????????}

????????//計(jì)算機(jī)價(jià)格為8800元

????????public static double ComputerPrice()

????????{

????????????return 8800.0;

????????}

????}

以上代碼實(shí)現(xiàn)了對(duì)于100元以上商品的的88折處理惑芭。一方面為了給GetPriceHandler綁定方法就必須將委托聲明為public坠狡,但是一旦聲明為public

就可以在類外部直接通過Invoke來調(diào)用該委托所綁定的方法,而產(chǎn)生我們不需要的結(jié)果

當(dāng)然我們可以將GetPriceHandler聲明為private并且通過public 的addHandler,removeHandler來消除委托public的副作用遂跟,但是C#提供了更加優(yōu)雅的方法:

那就是event關(guān)鍵字逃沿。

事件(event)可被視作為一種特別的委托,它為委托對(duì)象隱式地建立起add_XXX幻锁、remove_XXX 兩個(gè)方法凯亮,用作注冊(cè)與注銷事件的處理方法。而且事件對(duì)應(yīng)的變量成員將會(huì)被視為 private 變量哄尔,外界無法超越事件所在對(duì)象直接訪問它們假消,這使事件具備良好的封裝性,而且免除了add_XXX究飞、remove_XXX等繁瑣的代碼置谦。

public class EventTest

????{

????????public delegate void MyDelegate();

????????public event MyDelegate MyEvent;

????}

觀察事件的編譯過程可知,在編譯的時(shí)候亿傅,系統(tǒng)為 MyEvent 事件自動(dòng)建立add_MyEvent媒峡、remove_MyEvent 方法。

使用

事件能通過+=和-=兩個(gè)方式注冊(cè)或者注銷對(duì)其處理的方法葵擎,使用+=與-=操作符的時(shí)候谅阿,系統(tǒng)會(huì)自動(dòng)調(diào)用對(duì)應(yīng)的 add_XXX、remove_XXX 進(jìn)行處理。

值得留意签餐,在PersonManager類的Execute方法中寓涨,如果 MyEvent 綁定的處理方法不為空,即可使用MyEvent(string)引發(fā)事件氯檐。但如果在外界的 main 方法中直接使用 personManager.MyEvent (string) 來引發(fā)事件戒良,系統(tǒng)將引發(fā)錯(cuò)誤報(bào)告。這正是因?yàn)槭录邆淞肆己玫姆庋b性冠摄,使外界不能超越事件所在的對(duì)象訪問其變量成員糯崎。

注意:在事件所處的對(duì)象之外,事件只能出現(xiàn)在+=河泳,-=的左方沃呢。

public delegate void MyDelegate(string name);

????public class PersonManager

????{

????????public event MyDelegate MyEvent;

????????//執(zhí)行事件

????????public void Execute(string name)

????????{

????????????if (MyEvent != null)

????????????????MyEvent(name);

????????}

????}

????class Program

????{

????????static void Main(string[] args)

????????{

????????????PersonManager personManager = new PersonManager();

????????????//綁定事件處理方法

????????????personManager.MyEvent += new MyDelegate(GetName);

????????????personManager.Execute("Leslie");

????????}

????????public static void GetName(string name)

????????{

????????????Console.WriteLine("My name is " + name);

????????}

????}

在綁定事件處理方法的時(shí)候,事件出現(xiàn)在+=拆挥、-= 操作符的左邊薄霜,對(duì)應(yīng)的委托對(duì)象出現(xiàn)在+=、-= 操作符的右邊纸兔。對(duì)應(yīng)以上例子惰瓜,事件提供了更簡(jiǎn)單的綁定方式,只需要在+=汉矿、-= 操作符的右方寫上方法名稱鸵熟,系統(tǒng)就能自動(dòng)辯認(rèn)。

public delegate void MyDelegate(string name);

????public class PersonManager

????{

????????public event MyDelegate MyEvent;

????????.........

????}

????class Program

????{

????????static void Main(string[] args)

????????{

????????????PersonManager personManager = new PersonManager();

????????????//綁定事件處理方法

????????????personManager.MyEvent += GetName;

????????????.............

????????}

????????public static void GetName(string name)

????????{.........}

???}

如果覺得編寫 GetName 方法過于麻煩负甸,你還可以使用匿名方法綁定事件的處理。

public delegate void MyDelegate(string name);

????public class PersonManager

????{

????????public event MyDelegate MyEvent;

????????//執(zhí)行事件

????????public void Execute(string name)

????????{

????????????if (MyEvent != null)

????????????????MyEvent(name);

????????}

????????static void Main(string[] args)

????????{

????????????PersonManager personManager = new? ? ? PersonManager();

????????????//使用匿名方法綁定事件的處理

????????????personManager.MyEvent += delegate(string name){

????????????????Console.WriteLine("My name is "+name);

????????????};

????????????personManager.Execute("Leslie");

????????}

????}

lamda表達(dá)式

在Framework 2.0 以前痹届,聲明委托的唯一方法是通過方法命名呻待,從Framework 2.0 起,系統(tǒng)開始支持匿名方法队腐。

通過匿名方法蚕捉,可以直接把一段代碼綁定給事件,因此減少了實(shí)例化委托所需的編碼系統(tǒng)開銷柴淘。

而在 Framework 3.0 開始迫淹,Lambda 表達(dá)式開始逐漸取代了匿名方法,作為編寫內(nèi)聯(lián)代碼的首選方式为严×舶荆總體來說,Lambda 表達(dá)式的作用是為了使用更簡(jiǎn)單的方式來編寫匿名方法第股,徹底簡(jiǎn)化委托的使用方式应民。

使用匿名方法

public delegate void MyDelegate(string name);

public class PersonManager

{

??public event MyDelegate MyEvent;

??.........

}

static void Main(string[] args)

{

????PersonManager personManager = new PersonManager();

?? //使用匿名方法綁定事件的處理

?? personManager.MyEvent += delegate(string name){

?? Console.WriteLine("My name is "+name);

????};

}

使用lambda表達(dá)式

static void Main(string[] args)

{

????PersonManager personManager = new PersonManager();

?? //使用lambda表達(dá)式

?? personManager.MyEvent += (name) =>{

?? Console.WriteLine("My name is "+name);

????};

}

常用泛型委托:

Action此委托由系統(tǒng)提供 無需聲明Action 支持0~16個(gè)參數(shù),可以按需求任意使用。public delegate void Action()public delegate void Action(T1 obj1)public delegate void Action(T1 obj1, T2 obj2)public delegate void Action(T1 obj1, T2 obj2诲锹,T3 obj3)............public delegate void Action(T1 obj1, T2 obj2繁仁,T3 obj3,......归园,T16 obj16)static void Main(string[] args)????????{????????????int x = 1000;????????????Action action = () => x = x + 500;????????????action.Invoke();????????????Console.WriteLine("Result is : " + x);????????}static void Main(string[] args)????????{????????????Action action = (x) =>

????????????{

????????????????x = x + 500;

????????????????Console.WriteLine("Result is : " + x);

????????????};

????????????action(1000);

????????}

委托 Func 與 Action 相似黄虱,同樣支持 0~16 個(gè)參數(shù),不同之處在于Func 必須具有返回值public delegate TResult Func()public delegate TResult Func(T1 obj1)public delegate TResult Func(T1 obj1,T2 obj2)public delegate TResult Func(T1 obj1,T2 obj2,T3 obj3)............public delegate TResult Func(T1 obj1,T2 obj2,T3 obj3,......,T16 obj16)static void Main(string[] args)????????{????????????Funcfunc = Account;????????????double result=func(1000, true);????????????Console.WriteLine("Result is : "+result);????????}????????static double Account(double a,bool condition)????????{????????????if (condition)????????????????return a * 1.5;????????????else????????????????return a * 2;????????}static void Main(string[] args){???? ??? Func func = (a,condition) =>

???? ??? {

???? ??? ??? if (condition)

???? ??? ??? {

???? ??? ??? ??? return a * 1.5;

???? ??? ??? }

???? ??? ??? else

???? ??? ??? {

???? ??? ??? ??? return a * 2;

???? ??? ??? }

???? ??? };

???? ??? double result=func(1000, true);

???? ??? Console.WriteLine("Result is : "+result);

?}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末庸诱,一起剝皮案震驚了整個(gè)濱河市捻浦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌偶翅,老刑警劉巖默勾,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異聚谁,居然都是意外死亡母剥,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門形导,熙熙樓的掌柜王于貴愁眉苦臉地迎上來环疼,“玉大人,你說我怎么就攤上這事朵耕§帕ィ” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵阎曹,是天一觀的道長伪阶。 經(jīng)常有香客問我,道長处嫌,這世上最難降的妖魔是什么栅贴? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮熏迹,結(jié)果婚禮上檐薯,老公的妹妹穿的比我還像新娘。我一直安慰自己注暗,他們只是感情好坛缕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捆昏,像睡著了一般赚楚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上骗卜,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天直晨,我揣著相機(jī)與錄音搀军,去河邊找鬼。 笑死勇皇,一個(gè)胖子當(dāng)著我的面吹牛罩句,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播敛摘,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼门烂,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了兄淫?” 一聲冷哼從身側(cè)響起屯远,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捕虽,沒想到半個(gè)月后慨丐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泄私,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年房揭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晌端。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捅暴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出咧纠,到底是詐尸還是另有隱情蓬痒,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布漆羔,位于F島的核電站梧奢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏演痒。R本人自食惡果不足惜粹断,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嫡霞。 院中可真熱鬧,春花似錦希柿、人聲如沸诊沪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽端姚。三九已至,卻和暖如春挤悉,著一層夾襖步出監(jiān)牢的瞬間渐裸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留昏鹃,地道東北人尚氛。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像洞渤,于是被迫代替她去往敵國和親阅嘶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 委托:其實(shí)就是一種命令载迄,A委托B讯柔,做事情的就是B * 上面是在現(xiàn)實(shí)世界里,反過來在程序世界中的 * 委托實(shí)際上就是...
    Unity開發(fā)閱讀 610評(píng)論 1 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理护昧,服務(wù)發(fā)現(xiàn)魂迄,斷路器,智...
    卡卡羅2017閱讀 134,633評(píng)論 18 139
  • 簡(jiǎn)易線程控制方法: 新建線程惋耙,無返回值捣炬,不帶參 Thread thread = new Thread(new Th...
    鑄劍悄悄對(duì)你說閱讀 852評(píng)論 1 0
  • 兒子 兒子識(shí)字很早,所以早早就能自己看書怠晴,不過大多時(shí)候他還是愿意和我一起看遥金,看不懂的地方就讓我給他講。 他三歲的時(shí)...
    美生活閱讀 293評(píng)論 2 4
  • 我要做一件事蒜田,需要兩三個(gè)人稿械。 清晨,提交最后一次結(jié)果冲粤,慶幸著比賽終于結(jié)束了美莫。但是我知道心里一直有一個(gè)念頭——訓(xùn)練一...
    佳樂change閱讀 1,529評(píng)論 0 3