关键词诊断优化全部关键词,上海做网站就用乐云seo,网站建设功能点价格,中信建设有限责任公司西安分公司上一篇说了一下委托#xff0c;这篇来说说局部函数和委托的对比。把委托和局部函数放成前后篇#xff0c;是因为这两个内容很像#xff0c;用起来容易混。需要了解委托相关内容#xff0c;可以看这一篇 【传送门】使用委托表达式(Lambda)假设一个场景#xff1a;我们有一个… 上一篇说了一下委托这篇来说说局部函数和委托的对比。 把委托和局部函数放成前后篇是因为这两个内容很像用起来容易混。需要了解委托相关内容可以看这一篇 【传送门】 使用委托表达式(Lambda)假设一个场景我们有一个订单列表里面有售价和采购价。我们需要计算所有物品的毛利率。public class OrderDetails
{public int Id { get; set; }public string ItemName { get; set; }public double PurchasePrice { get; set; }public double SellingPrice { get; set; }
}
通过迭代我们可以计算出每个项目的毛利率static void Main(string[] args)
{ListOrderDetails lstOrderDetails new ListOrderDetails();lstOrderDetails.Add(new OrderDetails() { Id 1, ItemName Item 1, PurchasePrice 100, SellingPrice 120 });lstOrderDetails.Add(new OrderDetails() { Id 2, ItemName Item 2, PurchasePrice 800, SellingPrice 1200 });lstOrderDetails.Add(new OrderDetails() { Id 3, ItemName Item 3, PurchasePrice 150, SellingPrice 150 });lstOrderDetails.Add(new OrderDetails() { Id 4, ItemName Item 4, PurchasePrice 155, SellingPrice 310 });lstOrderDetails.Add(new OrderDetails() { Id 5, ItemName Item 5, PurchasePrice 500, SellingPrice 550 });Funcdouble, double, double GetPercentageProfit (purchasePrice, sellPrice) (((sellPrice - purchasePrice) / purchasePrice) * 100);foreach (var order in lstOrderDetails){Console.WriteLine($Item Name: {order.ItemName}, Profit(%) : {GetPercentageProfit(order.PurchasePrice, order.SellingPrice)} );}
}
例子中我们创建了一个有5个商品的列表。我们还创建了一个委托表达式并在循环中调用。 我们来看看这个委托表达式在IL中是什么样子图上能很清楚看到Lambda被转换成了类。等等为什么lambda表达式被转成了类而不是一个方法这里需要划重点。Lambda表达式在IL中会被转为委托。而委托是一个类。关于委托为什么是一个类可以去看上一篇。这儿知道结论就好。所以Lambda表达式会转成一个类应该通过一个实例来使用。而这个实例是new出来的所以是分配在堆上的。另外通过IL代码我们也知道IL是使用虚方法callvirt来调用的这个表达式。 现在我们知道了一件事Lambda会被转成委托和类由这个类的一个实例来使用。这个对象的生命周期必须由GC来处理。使用局部函数(Local Function)上面的示例代码我们换成局部函数static void Main(string[] args)
{ListOrderDetails lstOrderDetails new ListOrderDetails();lstOrderDetails.Add(new OrderDetails() { Id 1, ItemName Item 1, PurchasePrice 100, SellingPrice 120 });lstOrderDetails.Add(new OrderDetails() { Id 2, ItemName Item 2, PurchasePrice 800, SellingPrice 1200 });lstOrderDetails.Add(new OrderDetails() { Id 3, ItemName Item 3, PurchasePrice 150, SellingPrice 150 });lstOrderDetails.Add(new OrderDetails() { Id 4, ItemName Item 4, PurchasePrice 155, SellingPrice 310 });lstOrderDetails.Add(new OrderDetails() { Id 5, ItemName Item 5, PurchasePrice 500, SellingPrice 550 });double GetPercentageProfit(double purchasePrice, double sellPrice){return (((sellPrice - purchasePrice) / purchasePrice) * 100);}foreach (var order in lstOrderDetails){Console.WriteLine($Item Name: {order.ItemName}, Profit(%) : {GetPercentageProfit(order.PurchasePrice, order.SellingPrice)} );}
}
现在我们在Main方法中放入了局部函数GetPercentageProfit。我们再检查下IL里的代码没有新类没有新对象只是一个简单的函数调用。此外Lambda表达式和局部函数的一个重要区别是IL中的调用方式。调用局部函数用call它比callvirt要快因为它是存储在堆栈上的而不是堆上。通常我们不需要关注IL如何运作但好的开发人员真的需要了解一些框架的内部细节。call和callvert的区别在于call不检查调用者实例是否存在而且callvert总是在调用时检查所以callvert不能调用静态类方法只能调用实例方法。 还是上面的例子这回我们用迭代器实现static void Main(string[] args)
{ListOrderDetails lstOrderDetails new ListOrderDetails();lstOrderDetails.Add(new OrderDetails() { Id 1, ItemName Item 1, PurchasePrice 100, SellingPrice 120 });lstOrderDetails.Add(new OrderDetails() { Id 2, ItemName Item 2, PurchasePrice 800, SellingPrice 1200 });lstOrderDetails.Add(new OrderDetails() { Id 3, ItemName Item 3, PurchasePrice 150, SellingPrice 150 });lstOrderDetails.Add(new OrderDetails() { Id 4, ItemName Item 4, PurchasePrice 155, SellingPrice 310 });lstOrderDetails.Add(new OrderDetails() { Id 5, ItemName Item 5, PurchasePrice 500, SellingPrice 550 });var result GetItemSellingPice(lstOrderDetails);foreach (string s in result){Console.WriteLine(s.ToString());}
}private static IEnumerablestring GetItemSellingPice(ListOrderDetails lstOrderDetails)
{if (lstOrderDetails null) throw new ArgumentNullException();foreach (var order in lstOrderDetails){yield return ($Item Name:{order.ItemName}, Selling Price:{order.SellingPrice});}
}
我们将列表传递给GetItemSellingPice。我们在方法中检查了列表不能为null并在循环中使用yield return返回数据。代码看起来没问题是吧那我们假设列表真的为空会怎么样呢应该会返回ArgumentNullException预期是这样。执行一下看看实际不是这样。当我们使用迭代器时方法并没有立即执行并返回异常而是在我们使用结果foreach (string s in result)时才执行并返回异常。这种情况会让我们对于异常的判断和处理出现错误。这时候局部函数就是一个好的解决方式static void Main(string[] args)
{var result GetItemSellingPice(null);foreach (string s in result){Console.WriteLine(s.ToString());}
}private static IEnumerablestring GetItemSellingPice(ListOrderDetails lstOrderDetails)
{if (lstOrderDetails null) throw new ArgumentNullException();return GetItemPrice();IEnumerablestring GetItemPrice(){foreach (var order in lstOrderDetails){yield return ($Item Name:{order.ItemName}, Selling Price:{order.SellingPrice});}}
}
现在我们正确地在第一时间得到异常。总结局部函数是一个非常强大的存在。它与Lambda表达式类似但有更优的性能。又是一个好东西是吧