成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Dotnet的局部函數(shù)和委托的對比

開發(fā) 前端
把委托和局部函數(shù)放成前后篇,是因為這兩個內(nèi)容很像,用起來容易混。

 [[380147]]

本文轉(zhuǎn)載自微信公眾號「老王Plus」,作者老王Plus的老王 。轉(zhuǎn)載本文請聯(lián)系老王Plus公眾號。

把委托和局部函數(shù)放成前后篇,是因為這兩個內(nèi)容很像,用起來容易混。

使用委托表達式(Lambda)

假設(shè)一個場景:我們有一個訂單列表,里面有售價和采購價。我們需要計算所有物品的毛利率。

  1. public class OrderDetails 
  2.     public int Id { get; set; } 
  3.     public string ItemName { get; set; } 
  4.     public double PurchasePrice { get; set; } 
  5.     public double SellingPrice { get; set; } 

通過迭代,我們可以計算出每個項目的毛利率:

  1. static void Main(string[] args) 
  2.     List<OrderDetails> lstOrderDetails = new List<OrderDetails>(); 
  3.  
  4.     lstOrderDetails.Add(new OrderDetails() { Id = 1, ItemName = "Item 1", PurchasePrice = 100, SellingPrice = 120 }); 
  5.     lstOrderDetails.Add(new OrderDetails() { Id = 2, ItemName = "Item 2", PurchasePrice = 800, SellingPrice = 1200 }); 
  6.     lstOrderDetails.Add(new OrderDetails() { Id = 3, ItemName = "Item 3", PurchasePrice = 150, SellingPrice = 150 }); 
  7.     lstOrderDetails.Add(new OrderDetails() { Id = 4, ItemName = "Item 4", PurchasePrice = 155, SellingPrice = 310 }); 
  8.     lstOrderDetails.Add(new OrderDetails() { Id = 5, ItemName = "Item 5", PurchasePrice = 500, SellingPrice = 550 }); 
  9.  
  10.     Func<doubledoubledouble> GetPercentageProfit = (purchasePrice, sellPrice) => (((sellPrice - purchasePrice) / purchasePrice) * 100); 
  11.  
  12.     foreach (var order in lstOrderDetails) 
  13.     { 
  14.         Console.WriteLine($"Item Name: {order.ItemName}, Profit(%) : {GetPercentageProfit(order.PurchasePrice, order.SellingPrice)} "); 
  15.     } 

例子中,我們創(chuàng)建了一個有5個商品的列表。我們還創(chuàng)建了一個委托表達式,并在循環(huán)中調(diào)用。

我們來看看這個委托表達式在IL中是什么樣子:

圖上能很清楚看到,Lambda被轉(zhuǎn)換成了類。

等等,為什么lambda表達式被轉(zhuǎn)成了類,而不是一個方法?

這里需要劃重點。Lambda表達式,在IL中會被轉(zhuǎn)為委托。而委托是一個類。關(guān)于委托為什么是一個類,可以去看上一篇。這兒知道結(jié)論就好。

所以,Lambda表達式會轉(zhuǎn)成一個類,應(yīng)該通過一個實例來使用。而這個實例是new出來的,所以是分配在堆上的。

另外,通過IL代碼我們也知道,IL是使用虛方法callvirt來調(diào)用的這個表達式。

現(xiàn)在,我們知道了一件事:Lambda會被轉(zhuǎn)成委托和類,由這個類的一個實例來使用。這個對象的生命周期必須由GC來處理。

使用局部函數(shù)(Local Function)

上面的示例代碼,我們換成局部函數(shù):

  1. static void Main(string[] args) 
  2.     List<OrderDetails> lstOrderDetails = new List<OrderDetails>(); 
  3.  
  4.     lstOrderDetails.Add(new OrderDetails() { Id = 1, ItemName = "Item 1", PurchasePrice = 100, SellingPrice = 120 }); 
  5.     lstOrderDetails.Add(new OrderDetails() { Id = 2, ItemName = "Item 2", PurchasePrice = 800, SellingPrice = 1200 }); 
  6.     lstOrderDetails.Add(new OrderDetails() { Id = 3, ItemName = "Item 3", PurchasePrice = 150, SellingPrice = 150 }); 
  7.     lstOrderDetails.Add(new OrderDetails() { Id = 4, ItemName = "Item 4", PurchasePrice = 155, SellingPrice = 310 }); 
  8.     lstOrderDetails.Add(new OrderDetails() { Id = 5, ItemName = "Item 5", PurchasePrice = 500, SellingPrice = 550 }); 
  9.  
  10.     double GetPercentageProfit(double purchasePrice, double sellPrice) 
  11.     { 
  12.         return (((sellPrice - purchasePrice) / purchasePrice) * 100); 
  13.     } 
  14.  
  15.     foreach (var order in lstOrderDetails) 
  16.     { 
  17.         Console.WriteLine($"Item Name: {order.ItemName}, Profit(%) : {GetPercentageProfit(order.PurchasePrice, order.SellingPrice)} "); 
  18.     } 

現(xiàn)在,我們在Main方法中放入了局部函數(shù)GetPercentageProfit。

我們再檢查下IL里的代碼:

沒有新類,沒有新對象,只是一個簡單的函數(shù)調(diào)用。

此外,Lambda表達式和局部函數(shù)的一個重要區(qū)別是IL中的調(diào)用方式。調(diào)用局部函數(shù)用call,它比callvirt要快,因為它是存儲在堆棧上的,而不是堆上。

通常我們不需要關(guān)注IL如何運作,但好的開發(fā)人員真的需要了解一些框架的內(nèi)部細節(jié)。

call和callvert的區(qū)別在于,call不檢查調(diào)用者實例是否存在,而且callvert總是在調(diào)用時檢查,所以callvert不能調(diào)用靜態(tài)類方法,只能調(diào)用實例方法。

還是上面的例子,這回我們用迭代器實現(xiàn):

  1. static void Main(string[] args) 
  2.     List<OrderDetails> lstOrderDetails = new List<OrderDetails>(); 
  3.  
  4.     lstOrderDetails.Add(new OrderDetails() { Id = 1, ItemName = "Item 1", PurchasePrice = 100, SellingPrice = 120 }); 
  5.     lstOrderDetails.Add(new OrderDetails() { Id = 2, ItemName = "Item 2", PurchasePrice = 800, SellingPrice = 1200 }); 
  6.     lstOrderDetails.Add(new OrderDetails() { Id = 3, ItemName = "Item 3", PurchasePrice = 150, SellingPrice = 150 }); 
  7.     lstOrderDetails.Add(new OrderDetails() { Id = 4, ItemName = "Item 4", PurchasePrice = 155, SellingPrice = 310 }); 
  8.     lstOrderDetails.Add(new OrderDetails() { Id = 5, ItemName = "Item 5", PurchasePrice = 500, SellingPrice = 550 }); 
  9.  
  10.     var result = GetItemSellingPice(lstOrderDetails); 
  11.  
  12.     foreach (string s in result) 
  13.     { 
  14.         Console.WriteLine(s.ToString()); 
  15.     } 
  16.  
  17. private static IEnumerable<string> GetItemSellingPice(List<OrderDetails> lstOrderDetails) 
  18.     if (lstOrderDetails == null) throw new ArgumentNullException(); 
  19.  
  20.     foreach (var order in lstOrderDetails) 
  21.     { 
  22.         yield return ($"Item Name:{order.ItemName}, Selling Price:{order.SellingPrice}"); 
  23.     } 

我們將列表傳遞給GetItemSellingPice。我們在方法中檢查了列表不能為null,并在循環(huán)中使用yield return返回數(shù)據(jù)。

代碼看起來沒問題,是吧?

那我們假設(shè)列表真的為空,會怎么樣呢?應(yīng)該會返回ArgumentNullException,預(yù)期是這樣。

執(zhí)行一下看看,實際不是這樣。當我們使用迭代器時,方法并沒有立即執(zhí)行并返回異常,而是在我們使用結(jié)果foreach (string s in result)時,才執(zhí)行并返回異常。這種情況,會讓我們對于異常的判斷和處理出現(xiàn)錯誤。

這時候,局部函數(shù)就是一個好的解決方式:

  1. static void Main(string[] args) 
  2.     var result = GetItemSellingPice(null); 
  3.  
  4.     foreach (string s in result) 
  5.     { 
  6.         Console.WriteLine(s.ToString()); 
  7.     } 
  8.  
  9. private static IEnumerable<string> GetItemSellingPice(List<OrderDetails> lstOrderDetails) 
  10.     if (lstOrderDetails == null) throw new ArgumentNullException(); 
  11.  
  12.     return GetItemPrice(); 
  13.  
  14.     IEnumerable<string> GetItemPrice() 
  15.     { 
  16.         foreach (var order in lstOrderDetails) 
  17.         { 
  18.             yield return ($"Item Name:{order.ItemName}, Selling Price:{order.SellingPrice}"); 
  19.         } 
  20.     } 

現(xiàn)在,我們正確地在第一時間得到異常。

總結(jié)

局部函數(shù)是一個非常強大的存在。它與Lambda表達式類似,但有更優(yōu)的性能。

又是一個好東西,是吧?

 

責(zé)任編輯:武曉燕 來源: 老王Plus
相關(guān)推薦

2021-01-27 08:12:04

Dotnet函數(shù)數(shù)據(jù)

2021-03-10 07:20:44

數(shù)據(jù)定位匹配

2016-09-14 21:28:25

JavaScript事件代理委托

2010-03-15 09:32:56

Python函數(shù)

2009-08-20 18:11:08

C#異步委托

2020-11-11 21:26:48

函數(shù)變量

2009-08-18 10:54:17

C#事件和委托

2024-10-05 00:00:35

Action?C#Func?

2024-05-30 12:24:03

C#開發(fā)

2011-06-16 15:14:17

VB.NET事件委托

2009-09-08 15:28:24

C#委托

2011-03-23 17:11:21

Lampwamp

2024-09-29 09:28:38

Action?C#

2009-08-20 18:37:52

委托C#異步委托

2010-09-25 13:20:22

DHCP BOOTP

2021-03-03 08:13:57

模式垃圾回收

2024-06-28 10:19:02

委托事件C#

2013-03-19 09:48:38

C#

2009-03-12 09:05:18

接口C#.NET

2011-08-29 10:35:53

反射方式C#
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 91在线视频观看免费 | 天堂色 | 一道本视频 | 日韩高清三区 | 国产福利资源 | 97日日碰人人模人人澡分享吧 | 操久久 | 91久久综合亚洲鲁鲁五月天 | 黄色一级特级片 | 中文字幕免费视频 | 99精品视频免费在线观看 | 亚洲一区二区视频在线观看 | 国产精品久久久久久久久免费桃花 | 久久久精品网站 | 久久精品国产一区 | 国产一区二区三区免费 | 亚洲啊v在线 | 免费黄色片视频 | 国产专区在线 | 亚洲福利 | 九九在线视频 | av激情影院| 免费小视频在线观看 | 久久久久国产一区二区三区四区 | 欧美一区二区三区在线 | 99精品欧美一区二区蜜桃免费 | 亚洲一二三区免费 | 国产精品福利在线观看 | 日韩av在线一区二区 | 秋霞av国产精品一区 | 国产高清在线观看 | 国产一二区视频 | 国产精品美女久久久久aⅴ国产馆 | 看黄在线| 日韩欧美亚洲 | 国产一区在线视频 | 在线播放一区二区三区 | 久久精品亚洲欧美日韩精品中文字幕 | 日韩在线免费视频 | 一级看片免费视频囗交动图 | 色视频网站 |