Dotnet的局部函数和委托的对比

上一篇说了一下委托,这篇来说说局部函数和委托的对比。

把委托和局部函数放成前后篇,是因为这两个内容很像,用起来容易混。

需要了解委托相关内容,可以看这一篇 【传送门】

使用委托表达式(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)
{List<OrderDetails> lstOrderDetails = new List<OrderDetails>();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 });Func<double, 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)
{List<OrderDetails> lstOrderDetails = new List<OrderDetails>();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如何运作,但好的开发人员真的需要了解一些框架的内部细节。

callcallvert的区别在于,call不检查调用者实例是否存在,而且callvert总是在调用时检查,所以callvert不能调用静态类方法,只能调用实例方法。

还是上面的例子,这回我们用迭代器实现:

static void Main(string[] args)
{List<OrderDetails> lstOrderDetails = new List<OrderDetails>();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 IEnumerable<string> GetItemSellingPice(List<OrderDetails> 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 IEnumerable<string> GetItemSellingPice(List<OrderDetails> lstOrderDetails)
{if (lstOrderDetails == null) throw new ArgumentNullException();return GetItemPrice();IEnumerable<string> GetItemPrice(){foreach (var order in lstOrderDetails){yield return ($"Item Name:{order.ItemName}, Selling Price:{order.SellingPrice}");}}
}

现在,我们正确地在第一时间得到异常。

总结

局部函数是一个非常强大的存在。它与Lambda表达式类似,但有更优的性能。

又是一个好东西,是吧?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/305171.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA设置新视口,java – 在更大的图像上移动视口; JLablel JScrollPane

这是一个非常基本的例子.它使用一个图像文件并将其放置在一个滚动窗格内(在一个圆形的方式).从那里,它只是使用Swing Timer来随机生成点(在图像的边界内).每次生成一个新点时,我只需使用scrollToRectVisible,传递它想要渲染的点的位置和大小.这将确保新点(和点)在滚动窗格中可见…

经纬度 c代码中定义_如何将TXT文本格式的批量经纬度值导入到奥维成为标签

文本编辑&#xff1a;示例1&#xff1a;最基本的&#xff0c;只批量导入WGS-84经纬度值成为标签&#xff0c;不需要导入标签名称。 文本编辑格式&#xff1a;经度值空格纬度值换行&#xff0c;如下图&#xff1a;示例2&#xff1a;除WGS-84经纬度外&#xff0c;还要导入标签名称…

C# aspx页面动态加载ascx用户控件 及 利用反射调用其内方法

//控件代码 public partial class WebUserControl : System.Web.UI.UserControl { public void TestMethod(string strID) { this.TextBox1.Text " WebUserControl:" strID; //其他相关操作 } } //控件代码 public partial class WebU…

中国式创新技术“步态识别”终于来临,你大胆地走两步,我就知道你是谁

放完假的数据君&#xff0c;回到办公室&#xff0c;苦恼该码一篇什么文章&#xff0c;来给各位送上“节后的祝福”。 这么想着&#xff0c;数据君便开始浏览最新的科技报道&#xff1a; 什么鬼&#xff01;这难道是什么新兴的黑科技吗&#xff1f;&#xff01; 数据君赶紧查了…

帆软获取上月的第一天与最后一天_《原神》岩港打工第一天怎么玩 岩港打工第一天玩法攻略...

《原神》在11月2日开启了岩港奇珍行记&#xff0c;玩家可以在璃月港进行打工了&#xff0c;可能有的小伙伴还不清楚第一天的打工要怎么做&#xff0c;所以小编这次就为大家带来了《原神》岩港打工第一天玩法攻略&#xff0c;感兴趣的小伙伴可以来看一下。岩港打工第一天玩法攻略…

AgileConfig - RESTful API 介绍

AgileConfigAgileConfig是一个基于.net core开发的轻量级配置中心。AgileConfig秉承轻量化的特点&#xff0c;部署简单、配置简单、使用简单、学习简单&#xff0c;它只提取了必要的一些功能&#xff0c;并没有像Apollo那样复杂且庞大。但是它的功能也已经足够你替换webconfig&…

mysql卸载时弹框,win10卸载mysql5安装mysql8

使用mysql5的过程中使用 datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP 无法执行&#xff0c;原因是版本问题&#xff0c;因此我需要安装更高级的版本。一、卸载原有的mysql1、在控制面板中卸载mysql2、运行“regedit”文件&#xff0c;删除HKEY_LOCAL_MACHINE\SYSTEM\Co…

感谢Adobe,用上了Silverlight RC0版本

Adobe 23号发布CS4系列&#xff0c;24号网络上出现下载&#xff0c; MicorSoft 25号发布Silverlight RC0&#xff0c;26号网络上出现下载。 用上了Silverlight RC0&#xff0c; 真的要感谢Adobe&#xff0c;推出全新体验的Adobe Flash CS4正式版&#xff0c;也是Flash 10&#…

css中的单位换算_金蝶ERP入门教程:动态换算率及辅助计量单位的应用

金蝶ERP入门教程&#xff1a;动态换算率及辅助计量单位的应用关注我&#xff0c;我将定期分享更多的ERP解决方案如果您喜欢且觉得内容有用&#xff0c;请点击分享转发如果你有什么关于ERP系统的问题和疑问&#xff0c;可私信联系我大家好&#xff0c;我是Eric顾问哥&#xff1a…

因为加班,谈了7年的女友跟我分手了……

记得有一句很流行的话&#xff1a; 世界那么大&#xff0c;我想去看看 此时的你&#xff0c;走到了哪里&#xff1f; 还是停留在这里吗&#xff1f; 世界很小&#xff0c;小到仅有这几尺办公桌 工作很多&#xff0c;多到生活只余下工作 最近&#xff0c;腾讯上线了一支视频广告…

cf鼠标宏数据大全_游戏鼠标中的跑车,贱驴125M游戏鼠标体验!

如今全民玩游戏的年代&#xff0c;每个年轻人对自己玩游戏的装备也越来越看重。也越来越喜欢在这方面花钱&#xff0c;因为高手过招输赢本就在毫厘之间&#xff0c;如果能够拥有一款性能更强&#xff0c;使用更顺手的游戏装备&#xff0c;在玩游戏竞赛中&#xff0c;无疑有多了…

如何使用 Entity Framework 的 DbContext

微软的 Entity Framework 是一个开源的 对象-关系映射 ORM 框架&#xff0c;它帮助我们打通了 数据库的数据模型 到 代码层的领域模型&#xff0c;Entity Framework 简化了应用程序对数据库的 CURD 操作&#xff0c;而且还向高层屏蔽了数据是如何持久化到数据库的。说的具体一点…

php绘制饼图,php怎么绘制饼图?

php怎么绘制饼图&#xff1f;在php中&#xff0c;可以使用GD绘制饼图。GD库是php处理图形的扩展库&#xff0c;GD库提供了一系列用来处理图片的API&#xff0c;使用GD库可以处理图片&#xff0c;或者生成图片&#xff0c;也可以给图片加水印。PHP中用GD绘制饼图&#xff0c;绘制…

silklabo哪个公众号有资源_微小说免费渣渣团资源公众号看大全集

“免费小说全本”公众号。小说免费阅读吧|免费小说在线阅读网|免费小说资源|小说传送站&#xff5c;小说免费公众号推荐&#xff5c;免费小说全集书城推荐&#xff5c;免费小说公众号渣渣团&#xff5c;小说免费阅读叶辰萧初然|霸道总裁&#xff5c;先生是谁等全免费&#xff5…

Oracle 10R2 研究--db_file_multiblock_read_count对成本的影响

当研究oracle的查找方式中发现&#xff0c;在全表扫描和索引扫描时&#xff0c;会用到db_file_multiblock_read_count来一次读取多个IO。也看了一些关于db_file_multiblock_read_count的文章&#xff0c;为加深自己的理解&#xff0c;特做个试验研究。 以下是reference对它的解…

python视频实战_reboot第五期Python实战班视频_IT教程网

资源名称&#xff1a;reboot第五期Python实战班视频教程内容&#xff1a;第一章内容Hello Python上手简单脚本游戏 图形 WEB 你能想到的方方面面PYTHON都可以实现github上python的项目也足够多运行速度不是瓶颈课程实战目标python的基础,掌握基本的编程思想,具体的任务ACCESS_L…

大数据分析苏轼,你没看错,这些都是小学生完成的

适逢苏轼先生诞辰980周年&#xff0c;清华附小开展了一系列致敬苏轼的活动。同学们利用假期时间共完成课题研究报告23份&#xff1a;《大数据帮你进一步认识苏轼》、《苏轼的朋友圈》、《苏轼的旅游品牌价值分析》、《苏轼vs李白》等。是的&#xff0c;你没看错&#xff0c;这些…

深度解读.NET 5授权中间件的执行策略

前文提要2021.1月份我写了一个《这难道不是.NET5 的bug? 在线求锤&#xff1f;》&#xff0c;讲述了我在实现[全局授权访问特例匿名访问] 遇到的技术困惑: [特例匿名访问&#xff0c;怎么走了认证流程&#xff1f;]。博客园上某大佬的看法&#xff1a;大概的意思是说 &…

php myadmin怎么用,关于apachemysqlphpmyadmin的安装与配置

版本&#xff1a;apache_2.2.6-win32-x86-no_sslmysql-essential-5.0.45-win32php-5.2.5-Win32phpMyAdmin-2.11.3-all-languages版本不一样&#xff0c;配置多少会有些差异&#xff0c;但不会很大&#xff0c;大同小异罢了&#xff0c;但尽量还是要从官方网站上下载&#xff0c…

噪声与振动控制工程手册_仨亿技术丨工程机械噪声与控制分析

随着我国经济的发展&#xff0c;各种工程规模不断扩大、数量不断增多&#xff0c;这些工程在造福于人们并促进我国综合国力提高的同时&#xff0c;也在一定程度上带来一些工程机械噪声的问题。工程机械噪声的存在&#xff0c;不仅给工程机械的使用寿命带来不利影响&#xff0c;…