日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#中的委托,匿名方法和Lambda表达式

發(fā)布時間:2025/7/14 C# 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#中的委托,匿名方法和Lambda表达式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
簡介在.NET中,委托,匿名方法和Lambda表達式很容易發(fā)生混淆。我想下面的代碼能證實這點。下面哪一個First會被編譯?哪一個會返回我們需要的結果?即Customer.ID=5.答案是6個First不僅被編譯,并都獲得正確答案,且他們的結果一樣。如果你對此感到困惑,那么請繼續(xù)看這篇文章。 class Customer { public int ID { get; set; } public static bool Test(Customer x) { return x.ID == 5; } } ... List<Customer> custs = new List<Customer>(); custs.Add(new Customer() { ID = 1 }); custs.Add(new Customer() { ID = 5 }); custs.First(new Func<Customer, bool>(delegate(Customer x) { return x.ID == 5; })); custs.First(new Func<Customer, bool>((Customer x) => x.ID == 5)); custs.First(delegate(Customer x) { return x.ID == 5; }); custs.First((Customer x) => x.ID == 5); custs.First(x => x.ID == 5); custs.First(Customer.Test); 什么是委托?現在你定義一個處理用戶訂單的購物車ShoppingCart類。管理層決定根據數量,價格等給客人折扣。做為其中的一部分,他們已經實現了處理訂單時你要考慮一方面。不用考慮過多,你簡單聲明一個變量來保存有“吸引力的折扣”(magicDisCount),然后實現邏輯。 class Program { static void Main(string[] args) { new ShoppingCart().Process(); } } class ShoppingCart { public void Process() { int magicDiscount = 5; // ... } }第二天,異想天開的管理層決定根據購買時間調整折扣。這個很簡單,但需要你改動一點代碼。 class ShoppingCart { public void Process() { int magicDiscount = 5; if (DateTime.Now.Hour < 12) { magicDiscount = 10; } } }接下來一段時間里,管理層又反復添加更多的折扣邏輯。這時你就會在心理抱怨“受夠了”。那么我該怎么做才能把這些無聊的邏輯從我的代碼中剝離出去,讓該處理的人去處理呢?這時你要做的是移交或者委派給相應職能的別人。幸運的是,.NET為此提供了一種叫做“委托”的機制。委托如果你有C/C++編程背景,描述委托最好的方法是“函數指針”。對所有人來說,可以認為把委托傳遞給方法與把值或對象傳遞給方法一樣。比如下面三行代碼就表現出一樣的基本原則:你在傳遞數據給Process處理而不是你自己使用。 // 給方法Process傳遞一個整形值 Process( 5 ); // 給方法Process傳遞一個ArrayList的引用 Process( new ArrayList() ); // 給方法Process傳遞一個方法的引用 Process( discountDelegate );DiscountDelegate是什么?我如何創(chuàng)建?Process方法如何使用?首先如同聲明一個類一樣,聲明一個委托類型。 delegate int DiscountDelegate(); 這句話的意思是我們有一個叫DiscountDelegate的委托類型,我們可以像使用類,結構體等一樣使用它。它不需要數據參數,但返回一個整數值。像類一樣,我們必須創(chuàng)建一個它的實例它才有意義。記住,創(chuàng)建一個委托實例實質上是創(chuàng)建一個方法的引用。創(chuàng)建實例時關鍵是要明白DiscountDelegate沒有任何構造器,它有一個隱式的構造函數來構造一個與它相同簽名的方法(沒有傳入參數,返回一個整數)。那你怎么給這個構造函數一個方法呢?.NET向你提供了一個向它名字一樣簡單的方法,你所做的只是忽略圓括號。 1 DiscountDelegate discount = new DiscountDelegate(class.method); 在深入之前,先回到開始的例子,整理一個代碼。我們會添加一個Calculator類來幫助我們處理折扣邏輯,并給我們的委托提供一些方法。 delegate int DiscountDelegate(); class Program { static void Main(string[] args) { Calculator calc = new Calculator(); DiscountDelegate discount = null; if (DateTime.Now.Hour < 12) { discount = new DiscountDelegate(calc.Morning); } else if (DateTime.Now.Hour < 20) { discount = new DiscountDelegate(calc.Afternoon); } else { discount = new DiscountDelegate(calc.Night); } new ShoppingCart().Process(discount); } } class Calculator { public int Morning() { return 5; } public int Afternoon() { return 10; } public int Night() { return 15; } } class ShoppingCart { public void Process(DiscountDelegate discount) { int magicDiscount = discount(); // ... } }正如你所見,在Calculator類中,我們?yōu)槊總€邏輯分支創(chuàng)建了一個方法。在Main方法中,我們創(chuàng)建一個Calculator實例和一個DiscountDelegate實例,并按照我們所期望的把它們整合在一起。太棒了,我們不用擔心Process方法中的邏輯了,我們只需要簡單得回調我們定義的委托。記住!我們不關心委托是如何創(chuàng)建的(或什么時間),我們就像調用其他方法一樣調用它。如你所見,另一種理解委托的方法是,它延遲執(zhí)行一個方法。Calculator方法在過去某個時間本選擇,但不會執(zhí)行,直到我們調用discount()的時候。現在看看我們的解決方案,這里仍然存在一些丑陋的代碼。在Calculator類中,我們可以用一個不同的方法來返回替代每個有返回值得方法嗎?答案是肯定的,讓我們把這些亂糟糟的代碼合并起來。 delegate int DiscountDelegate(); class Program { static void Main(string[] args) { new ShoppingCart().Process(new DiscountDelegate(Calculator.Calculate)); } } class Calculator { public static int Calculate() { int discount = 0; if (DateTime.Now.Hour < 12) { discount = 5; } else if (DateTime.Now.Hour < 20) { discount = 10; } else { discount = 15; } return discount; } } class ShoppingCart { public void Process(DiscountDelegate discount) { int magicDiscount = discount(); // ... } }這樣子看起來更好點。你會注意到我們用一個靜態(tài)的Calculate方法替換了所有原來的方法,在Main方法中也不用費心維護一個指向DiscountDelegate的引用。現在你明白了所有關于委托的東西了嗎?在2004年.NET1.1中可以這么說,但是很不幸的是,這種框架自那以后更加成熟了。燈光,鏡頭,開始 或者我們需要Func!微軟在.NET 2.0中引入了泛型,并提供了一個泛型委托:Action<T>。老實說,我認為它遠不夠用。后來在.NET 3.5中,它為我們提供了一些我們不想定義的通用委托。他們擴展了Action,并添加了Func,二者唯一區(qū)別在于Func型方法有一個返回值而Action型方法沒有。這意味著我們不需要聲明自己的DiscountDelegate,可以用Func<int>替代。為說明這些觀點是如何工作的,我們來假設管理層又一次改變了我們的邏輯,我們需要提供一些特殊的折扣。很簡單,我們將給Calculate方法傳入一個bool型值。現在我們的委托簽名變成Func<bool,int>。注意Calculate方法現在包含一個bool型參數,我們用一個bool值調用discount()。 class Program { static void Main(string[] args) { new ShoppingCart().Process(new Func<bool, int>(Calculator.Calculate)); } } class Calculator { public static int Calculate(bool special) { int discount = 0; if (DateTime.Now.Hour < 12) { discount = 5; } else if (DateTime.Now.Hour < 20) { discount = 10; } else if (special) { discount = 20; } else { discount = 15; } return discount; } } class ShoppingCart { public void Process(Func<bool,int> discount) { int magicDiscount = discount(false); int magicDiscount2 = discount(true); } }好像還算不錯,我們又省了一行代碼,這樣算結束了嗎?當然沒有,我們甚至能省掉類型判斷。只要我們傳遞的方法有嚴格簽名的委托,.NET允許我們完全忽略掉顯式創(chuàng)建Func<bool,int> //因為Process期望的方法有一個bool型輸入參數和返回一個int值,所以下面這句話是正確的 new ShoppingCart().Process(Calculator.Calculate); 至此,首先通過忽略自定義委托,我們省略了代碼;然后排出了明確的創(chuàng)建Func委托。我們能繼續(xù)壓縮代碼行嗎?到此我們才完成此文的一半,答案顯然是“能”。匿名方法匿名方法能夠讓你聲明一個方法體而不需要給它指定一個名字。在接下來的場景里,它們以一個“普通的”方法存在;但是在你的代碼中沒有任何方法顯式調用它。匿名方法只能在使用委托的時候創(chuàng)建,事實上,它們通過delegate關鍵字創(chuàng)建。 class Program { static void Main(string[] args) { new ShoppingCart().Process( new Func<bool, int>(delegate(bool x) { return x ? 10 : 5; } )); } }正如你所見,我們完全刪除了Calculator類的需求。你可以在打括號中添加任何其他方法中的邏輯。如果你在看它如何執(zhí)行時有困難,那就把delegate(bool x)做為一個方法簽名,而不是一個關鍵字。設想這段代碼在一個類里,delegate(bool x){return 5;}是一個完整的合法方法聲明(我們確實有一個返回值),恰好delegate是一個保留字,在這里,它讓這個方法匿名。至此,我確信現在你知道這里我們甚至能壓縮更多的代碼。順利成章的,我們能忽略顯式聲明Func委托的需要;.NET讓我們使用delegate關鍵字更方便。 class Program { static void Main(string[] args) { new ShoppingCart().Process( delegate(bool x) { return x ? 10 : 5; } ); } }當把.NET方法做為委托參數時或處理時間時,就能看到匿名方法的真正用處。之前,你會為你所關注的所有可能行為創(chuàng)建了一個方法,現在你僅需以內聯的方式創(chuàng)建它們,并可以避免污染你的命名空間。 // 創(chuàng)建一個匿名比對方法 custs.Sort(delegate(Customer c1, Customer c2) { return Comparer<int>.Default.Compare(c1.ID, c2.ID); }); // 創(chuàng)建一個匿名事件 button1.Click += delegate(object o, EventArgs e) { MessageBox.Show("Click!"); }; Lambda 表達式MSDN中寫道:“Lambda 表達式”是一個匿名函數,它可以包含表達式和語句,并且可用于創(chuàng)建委托或表達式樹類型。你應當明白“用戶創(chuàng)建委托”部分,但什么是“表達式”呢?老實說,表達式和表達式樹不在此為討論范圍內。現在我們唯一需要明白的是,表達式是.NET程序運行時表示數據或對象的代碼(C#代碼)。引用Jon Skeet的話:“表達式樹是一種表達邏輯,這樣其他的代碼可以查詢的方法。當一個lambda表達式轉換成一個表達式樹,編譯器不會發(fā)出了lambda表達式的白細胞介素,它會發(fā)出白細胞介素這將會建立一個表達式樹表示相同的邏輯。”我們需要關注的是Lambda表達式替換匿名方法,和其他的特性。回顧我們最后例子,我們已經在一行代碼里壓縮了處理整個折扣算法的邏輯。 class Program { static void Main(string[] args) { new ShoppingCart().Process( delegate(bool x) { return x ? 10 : 5; } ); } }你相信我們能讓這個更短嗎?Lambda表達式用'=>'運算符表明什么參數傳遞給表達式。編譯器進一步處理,允許我們忽略類型并自動替我們推斷這些類型。如果你有2個或更多個參數,你需要用圓括號:(x,y)=>。如果只有一個,你設置不需要這樣:x=> static void Main(string[] args) { Func<bool, int> del = x => x ? 10 : 5; new ShoppingCart().Process(del); } // 更短啦... static void Main(string[] args) { new ShoppingCart().Process(x => x ? 10 : 5); }就是這樣子。x被推斷為bool型,并且有返回值,因為Process接收一個Func<bool,int>。如果我們想實現像之前那樣的完整代碼塊,我們只需要加上大括號。 static void Main(string[] args) { new ShoppingCart().Process( x => { int discount = 0; if (DateTime.Now.Hour < 12) { discount = 5; } else if (DateTime.Now.Hour < 20) { discount = 10; } else if(x) { discount = 20; } else { discount = 15; } return discount; }); } 寫在最后使用與不使用大括號有一個重要的不同。當你用時,你創(chuàng)建一個“語句Lambda”,反之,它是"表達Lambda"。語句Lambda能執(zhí)行多條語句(因此需要大括號),但不能創(chuàng)建表達樹。你可能只在使用IQueryable接口是遇到這個問題。下面的例子說明這個問題。 List<string> list = new List<string>(); IQueryable<string> query = list.AsQueryable(); list.Add("one"); list.Add("two"); list.Add("three"); string foo = list.First(x => x.EndsWith("o")); string bar = query.First(x => x.EndsWith("o")); // foo and bar are now both 'two' as expected foo = list.First(x => { return x.EndsWith("e"); }); //no error bar = query.First(x => { return x.EndsWith("e"); }); //error bar = query.First((Func<string,bool>)(x => { return x.EndsWith("e"); })); //no error 倒數第二行在編譯時失敗。這是因為IQueryable.First期望得到一個表達式作為參數,然而List<T>.First期望得到一個委托。你可以按照最后一行強制轉換Lambda到一個委托(使用First的方法重載)。這里很難結束討論,但是我覺得必須停止。Lambda大體上分為兩類:一類創(chuàng)建匿名方法和委托;另一類創(chuàng)建表達式。表達式自成一體,并不是.NET開發(fā)者的必備知識(無疑在LINQ中已有實現)。備注:此文為CodeProject上的同名文章<C# Delegates,Anonymous Methods, and Lambda Expressions>,個人覺得非常好,所以就翻一下給不想看英文的同學。由于能力有限,翻譯的不好,望大家多多包涵。

?

轉載于:https://www.cnblogs.com/vinsonLu/p/3664174.html

總結

以上是生活随笔為你收集整理的C#中的委托,匿名方法和Lambda表达式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产一区二区成人 | 黑人一级片 | 亚洲人性生活视频 | 激情婷婷综合 | 一区二区视频免费在线观看 | 超碰最新在线 | 色先锋av | 色视频免费 | 丰满少妇一区二区三区 | 插吧插吧综合网 | 91丨九色丨丰满 | 国产高清视频在线免费观看 | 中文精品在线 | 嫩模被强到高潮呻吟不断 | 高清在线一区二区 | 成年人高清视频 | 影音先锋亚洲一区 | 久久精品在线 | 色涩视频在线观看 | 久久视频黄色 | 久久精品视屏 | 欧美色视频在线 | 顶级毛片 | 成人免费黄色网 | 国产精品视频久久 | 欧美精品日韩精品 | 精品人妻一区二区三区四区 | 欧美混交群体交 | 蜜桃视频在线入口www | 涩涩视频在线观看 | 五月开心激情网 | 欲色av| 亚洲欧美一区二区三区情侣bbw | 成人资源站 | 久久青青草原 | 嫩草伊人久久精品少妇av | 综合狠狠 | 精品一区二区在线观看 | 欧美性生交xxxxx久久久 | 黄色小视频免费看 | 天天爱av| 日韩午夜在线视频 | 亚洲免费在线看 | 欧美高h | 欧美一极片 | 日韩激情一区二区三区 | 免费看国产精品 | 午夜精品久久久久久久96蜜桃 | 欧美激情3p | 又色又爽又黄无遮挡的免费视频 | 黄色成年视频 | 一级影片在线观看 | 人与动物黄色片 | 91麻豆精品国产理伦片在线观看 | 嫩模被强到高潮呻吟不断 | 波多野结衣一二三四区 | www.猫咪av.com | 中文在线а√在线8 | 捆绑最紧bdsm视频 | 精品三级视频 | www.成人免费 | 成人av播放 | 制服丝袜在线播放 | 国产视频精品在线 | 欧美日韩一区二区三区四区 | 草草视频在线播放 | 村姑电影在线播放免费观看 | 青青草手机在线观看 | 亚洲色中色 | 色香蕉网站 | 狠狠操中文字幕 | 色爽 av| 操日本老妇| 亚洲午夜视频在线观看 | 久久久久国产精品视频 | 好色av| 亚洲小说图片区 | 樱桃av | 亚州综合视频 | 成人精品亚洲 | 五月婷婷网站 | 中文字幕人妻无码系列第三区 | 午夜做爰xxxⅹ性高湖视频美国 | 成人免费毛片aaaaaa片 | 欧美日韩国产一级 | 久久久久一级片 | 国产真人毛片 | 欧美视频免费 | 尤物在线免费观看 | 国产男男一区二区三区 | 黄色三级a | 国产色站 | 伊人焦久影院 | 永久免费的av网站 | 叶爱在线 | 韩国中文字幕在线观看 | 欧美三级在线视频 | 久久一区欧美 | 风韵丰满熟妇啪啪区老熟熟女 |