反射获取 PropertyInfo 可以对对象的属性值进行读取或者写入,但是这样性能不好。所以,我们需要更快的方案。

方案说明

就是用表达式编译一个 Action<TObj,TValue> 作为 Setter,编译一个 Func<TObj,TValue> 作为 Getter。

然后把这些编译好的委托放在一个泛型类的静态字段中保存起来,需要使用的时候从这里面查找就可以了。

知识要点

  1. 使用表达式创建委托
  2. 泛型类的静态字段是每个闭合类型独立的,因此用于存储和类型相关的内容非常方便

实现代码

由于代码中混合的使用 Switch 作为字典的阴招,所以代码很长,此处不再罗列,仅给出链接:

基准测试

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
Intel Xeon CPU E5-2678 v3 2.50GHz, 1 CPU, 24 logical and 12 physical cores
.NET Core SDK=5.0.100-rc.2.20479.15
[Host] : .NET Core 2.1.23 (CoreCLR 4.6.29321.03, CoreFX 4.6.29321.01), X64 RyuJIT
net461 : .NET Framework 4.8 (4.8.4250.0), X64 RyuJIT
net48 : .NET Framework 4.8 (4.8.4250.0), X64 RyuJIT
netcoreapp21 : .NET Core 2.1.23 (CoreCLR 4.6.29321.03, CoreFX 4.6.29321.01), X64 RyuJIT
netcoreapp31 : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
netcoreapp5 : .NET Core 5.0.0 (CoreCLR 5.0.20.47505, CoreFX 5.0.20.47505), X64 RyuJIT

结论

  1. 使用委托明显比使用 PropertyInfo 要快,这个方案可以。
  2. Framework 真拉胯,Net 5 简直太强了。
  3. 如果属性是明确的,建议把字典中取出来的委托保存在自己的上下文,这可以明显的省去查找的消耗。

图表

从左往右分别是:直接读取属性、缓存委托、不缓存委托和使用 PropertyInfo。


数据

Getter

Method Job Runtime Mean Error StdDev Median Ratio RatioSD Rank
DirectlyString net461 .NET 4.6.1 0.1636 ns 0.0822 ns 0.1126 ns 0.1472 ns ? ? 2
DirectlyInt net461 .NET 4.6.1 0.0318 ns 0.0348 ns 0.0342 ns 0.0217 ns ? ? 1
ReflectString net461 .NET 4.6.1 145.8375 ns 2.2790 ns 2.1317 ns 145.6522 ns ? ? 7
ReflectInt net461 .NET 4.6.1 172.5066 ns 1.3206 ns 1.1028 ns 172.6804 ns ? ? 8
GetterString net461 .NET 4.6.1 31.4379 ns 0.6017 ns 0.5334 ns 31.6316 ns ? ? 4
GetterInt net461 .NET 4.6.1 33.0642 ns 0.4940 ns 0.4380 ns 33.0557 ns ? ? 5
GetterObject net461 .NET 4.6.1 33.9174 ns 0.5587 ns 0.5226 ns 33.7326 ns ? ? 6
GetterCached net461 .NET 4.6.1 7.5878 ns 0.1223 ns 0.1144 ns 7.5765 ns ? ? 3
                   
DirectlyString net48 .NET 4.8 0.0181 ns 0.0353 ns 0.0313 ns 0.0043 ns ? ? 1
DirectlyInt net48 .NET 4.8 0.0050 ns 0.0089 ns 0.0079 ns 0.0000 ns ? ? 1
ReflectString net48 .NET 4.8 143.8313 ns 2.2501 ns 2.1047 ns 143.5568 ns ? ? 5
ReflectInt net48 .NET 4.8 172.1714 ns 1.9819 ns 1.7569 ns 172.3142 ns ? ? 6
GetterString net48 .NET 4.8 31.5887 ns 0.6310 ns 0.5902 ns 31.5385 ns ? ? 3
GetterInt net48 .NET 4.8 32.7140 ns 0.3992 ns 0.3734 ns 32.7343 ns ? ? 4
GetterObject net48 .NET 4.8 33.3063 ns 0.2069 ns 0.1834 ns 33.3053 ns ? ? 4
GetterCached net48 .NET 4.8 7.5540 ns 0.2201 ns 0.1951 ns 7.5069 ns ? ? 2
                   
DirectlyString netcoreapp21 .NET Core 2.1 0.0000 ns 0.0000 ns 0.0000 ns 0.0000 ns ? ? 1
DirectlyInt netcoreapp21 .NET Core 2.1 0.0193 ns 0.0111 ns 0.0104 ns 0.0177 ns ? ? 2
ReflectString netcoreapp21 .NET Core 2.1 110.4180 ns 2.2159 ns 1.8503 ns 110.8038 ns ? ? 7
ReflectInt netcoreapp21 .NET Core 2.1 138.9612 ns 0.9694 ns 0.8594 ns 138.8217 ns ? ? 8
GetterString netcoreapp21 .NET Core 2.1 16.8958 ns 0.2384 ns 0.2230 ns 16.8103 ns ? ? 4
GetterInt netcoreapp21 .NET Core 2.1 19.4407 ns 0.2041 ns 0.1809 ns 19.4539 ns ? ? 6
GetterObject netcoreapp21 .NET Core 2.1 18.6922 ns 0.2700 ns 0.2255 ns 18.6582 ns ? ? 5
GetterCached netcoreapp21 .NET Core 2.1 0.9299 ns 0.0457 ns 0.0427 ns 0.9308 ns ? ? 3
                   
DirectlyString netcoreapp31 .NET Core 3.1 0.0000 ns 0.0000 ns 0.0000 ns 0.0000 ns ? ? 1
DirectlyInt netcoreapp31 .NET Core 3.1 0.0693 ns 0.0102 ns 0.0091 ns 0.0709 ns ? ? 2
ReflectString netcoreapp31 .NET Core 3.1 98.6735 ns 0.8335 ns 0.7389 ns 98.5319 ns ? ? 7
ReflectInt netcoreapp31 .NET Core 3.1 130.6941 ns 0.9332 ns 0.8730 ns 130.5376 ns ? ? 8
GetterString netcoreapp31 .NET Core 3.1 14.8915 ns 0.2025 ns 0.1795 ns 14.8911 ns ? ? 4
GetterInt netcoreapp31 .NET Core 3.1 16.2874 ns 0.0789 ns 0.0700 ns 16.2753 ns ? ? 5
GetterObject netcoreapp31 .NET Core 3.1 17.6202 ns 0.1130 ns 0.1057 ns 17.6092 ns ? ? 6
GetterCached netcoreapp31 .NET Core 3.1 0.6351 ns 0.0244 ns 0.0217 ns 0.6393 ns ? ? 3
                   
DirectlyString netcoreapp5 .NET Core 5.0 0.5098 ns 0.0328 ns 0.0291 ns 0.5131 ns 1.000 0.00 2
DirectlyInt netcoreapp5 .NET Core 5.0 0.0000 ns 0.0000 ns 0.0000 ns 0.0000 ns 0.000 0.00 1
ReflectString netcoreapp5 .NET Core 5.0 88.8937 ns 0.9697 ns 0.8596 ns 88.7457 ns 174.838 9.26 7
ReflectInt netcoreapp5 .NET Core 5.0 123.4464 ns 1.0582 ns 0.9898 ns 123.3193 ns 242.996 14.00 8
GetterString netcoreapp5 .NET Core 5.0 7.6628 ns 0.0931 ns 0.0777 ns 7.6703 ns 15.031 0.95 5
GetterInt netcoreapp5 .NET Core 5.0 6.6645 ns 0.0825 ns 0.0772 ns 6.6497 ns 13.085 0.69 4
GetterObject netcoreapp5 .NET Core 5.0 8.3090 ns 0.1685 ns 0.1576 ns 8.2865 ns 16.344 0.83 6
GetterCached netcoreapp5 .NET Core 5.0 0.9791 ns 0.0293 ns 0.0245 ns 0.9764 ns 1.920 0.13 3

Setter

Method Job Runtime Mean Error StdDev Median Ratio RatioSD Rank
DirectlyString net461 .NET 4.6.1 2.0161 ns 0.0300 ns 0.0266 ns 2.0045 ns 1.000 0.00 2
DirectlyInt net461 .NET 4.6.1 0.0076 ns 0.0094 ns 0.0083 ns 0.0081 ns 0.004 0.00 1
ReflectString net461 .NET 4.6.1 237.5006 ns 4.5706 ns 4.4890 ns 236.5912 ns 117.871 3.40 5
ReflectInt net461 .NET 4.6.1 249.3627 ns 2.1717 ns 2.0314 ns 249.0283 ns 123.681 1.94 6
GetterString net461 .NET 4.6.1 32.8621 ns 0.2855 ns 0.2229 ns 32.9189 ns 16.335 0.22 4
GetterInt net461 .NET 4.6.1 33.6103 ns 0.4245 ns 0.3544 ns 33.5499 ns 16.695 0.26 4
GetterObject net461 .NET 4.6.1 33.2561 ns 0.2966 ns 0.2629 ns 33.1795 ns 16.497 0.17 4
GetterCached net461 .NET 4.6.1 9.1805 ns 0.0761 ns 0.0674 ns 9.1802 ns 4.554 0.08 3
                   
DirectlyString net48 .NET 4.8 1.9272 ns 0.0298 ns 0.0264 ns 1.9245 ns 1.000 0.00 2
DirectlyInt net48 .NET 4.8 0.0000 ns 0.0000 ns 0.0000 ns 0.0000 ns 0.000 0.00 1
ReflectString net48 .NET 4.8 237.7686 ns 4.6597 ns 5.3661 ns 235.8445 ns 123.908 3.57 5
ReflectInt net48 .NET 4.8 249.6291 ns 4.5333 ns 4.2404 ns 249.5459 ns 129.689 3.13 6
GetterString net48 .NET 4.8 32.2366 ns 0.1941 ns 0.1721 ns 32.1780 ns 16.731 0.29 4
GetterInt net48 .NET 4.8 32.0081 ns 0.1488 ns 0.1162 ns 32.0270 ns 16.572 0.23 4
GetterObject net48 .NET 4.8 32.6413 ns 0.1417 ns 0.1183 ns 32.6260 ns 16.907 0.24 4
GetterCached net48 .NET 4.8 9.2589 ns 0.0928 ns 0.0868 ns 9.2564 ns 4.799 0.07 3
                   
DirectlyString netcoreapp21 .NET Core 2.1 2.4107 ns 0.0507 ns 0.0475 ns 2.3936 ns 1.000 0.00 2
DirectlyInt netcoreapp21 .NET Core 2.1 0.0007 ns 0.0028 ns 0.0025 ns 0.0000 ns 0.000 0.00 1
ReflectString netcoreapp21 .NET Core 2.1 203.6637 ns 3.6109 ns 3.3777 ns 203.4793 ns 84.517 2.31 7
ReflectInt netcoreapp21 .NET Core 2.1 213.8619 ns 2.1882 ns 1.9398 ns 213.7367 ns 88.757 1.71 8
GetterString netcoreapp21 .NET Core 2.1 19.5240 ns 0.0811 ns 0.0758 ns 19.5149 ns 8.102 0.15 5
GetterInt netcoreapp21 .NET Core 2.1 18.8794 ns 0.1193 ns 0.1058 ns 18.8837 ns 7.836 0.18 4
GetterObject netcoreapp21 .NET Core 2.1 20.6765 ns 0.2709 ns 0.2115 ns 20.6419 ns 8.584 0.14 6
GetterCached netcoreapp21 .NET Core 2.1 2.7606 ns 0.0613 ns 0.0512 ns 2.7590 ns 1.148 0.02 3
                   
DirectlyString netcoreapp31 .NET Core 3.1 2.2625 ns 0.0647 ns 0.0605 ns 2.2555 ns 1.000 0.00 2
DirectlyInt netcoreapp31 .NET Core 3.1 0.0072 ns 0.0165 ns 0.0146 ns 0.0000 ns 0.003 0.01 1
ReflectString netcoreapp31 .NET Core 3.1 182.7306 ns 3.3249 ns 3.1101 ns 182.3062 ns 80.804 1.99 7
ReflectInt netcoreapp31 .NET Core 3.1 192.2510 ns 2.3691 ns 2.1002 ns 191.4821 ns 85.061 2.88 8
GetterString netcoreapp31 .NET Core 3.1 16.9918 ns 0.2115 ns 0.1979 ns 16.9651 ns 7.516 0.25 5
GetterInt netcoreapp31 .NET Core 3.1 16.1168 ns 0.3558 ns 0.3654 ns 15.9822 ns 7.138 0.19 4
GetterObject netcoreapp31 .NET Core 3.1 19.3060 ns 0.4173 ns 0.5571 ns 19.4856 ns 8.480 0.45 6
GetterCached netcoreapp31 .NET Core 3.1 2.9276 ns 0.0156 ns 0.0146 ns 2.9313 ns 1.295 0.03 3
                   
DirectlyString netcoreapp5 .NET Core 5.0 2.2455 ns 0.0084 ns 0.0078 ns 2.2460 ns 1.000 0.00 2
DirectlyInt netcoreapp5 .NET Core 5.0 0.0000 ns 0.0000 ns 0.0000 ns 0.0000 ns 0.000 0.00 1
ReflectString netcoreapp5 .NET Core 5.0 162.8780 ns 0.7135 ns 0.6674 ns 162.8741 ns 72.538 0.45 7
ReflectInt netcoreapp5 .NET Core 5.0 171.1380 ns 0.4173 ns 0.3699 ns 171.1414 ns 76.217 0.31 8
GetterString netcoreapp5 .NET Core 5.0 8.6244 ns 0.1891 ns 0.1769 ns 8.5469 ns 3.841 0.08 5
GetterInt netcoreapp5 .NET Core 5.0 6.5511 ns 0.0347 ns 0.0325 ns 6.5634 ns 2.917 0.02 4
GetterObject netcoreapp5 .NET Core 5.0 9.0732 ns 0.0306 ns 0.0272 ns 9.0735 ns 4.041 0.02 6
GetterCached netcoreapp5 .NET Core 5.0 2.8223 ns 0.0728 ns 0.0681 ns 2.8190 ns 1.257 0.03 3

总结

使用表达式创建委托来取代 PropertyInfo 读取和写入属性效果很好。

开发者也可以直接引用 Newbe.ObjectVisitor 包来使用已经封装好的 ValueGetter 和 ValueSetter。

我只是知识的搬运工

发布说明

使用样例

番外分享

GitHub 项目地址:https://github.com/newbe36524/Newbe.ObjectVisitor

Gitee 项目地址:https://gitee.com/yks/Newbe.ObjectVisitor

寻找性能更优秀的动态 Getter 和 Setter 方案的更多相关文章

  1. Stylus-NodeJS下构建更富表现力/动态/健壮的CSS

    --------------------------本文来自张鑫旭大神博客------------------------------ 一.为什么我会讲Stylus,而不是SASS和LESS? SAS ...

  2. 比Kafka Mangaer更优秀的开源监控工具-Kafka Eagle

    比Kafka Mangaer更优秀的开源监控工具-Kafka Eagle 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在Kafka的监控系统中有很多优秀的开源监控系统.比如Kaf ...

  3. 通过AI自学习,Google让Pixel 3的人像模式更优秀

    通过AI自学习,Google让Pixel 3的人像模式更优秀 Link: https://news.cnblogs.com/n/613720/ 虽然双摄手机已经在市场上普及,其所带来的人像模式.多倍变 ...

  4. Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%。再往后,每提高0.1%,优化难度成指数级增长了。哪怕是千分之一,也直接影响用户体验,影响每天上万张机票的销售额。 在高并发场景下,提供了保证线程安全的对象、方法。比如经典的ConcurrentHashMap,它比起HashMap,有更小粒度的锁,并发读写性能更好。线程安全的StringBuilder取代S

    Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%.再往后,每提高0.1%,优化难度成指数级增长了.哪怕是千分之一,也直接影响用户体验,影响每天上万张机 ...

  5. Ember.js和Vue.js对比,哪个框架更优秀?

    本文由葡萄城技术团队于博客园翻译并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. JavaScript最初是为Web应用程序创建的.但是随着前端技术的 ...

  6. 异步IO比同步阻塞IO性能更好吗?为什么?

    最近在看node.js, 介绍中提到node是异步io的方式实现, 性能比同步阻塞io的更好. 对于一个request而言, 如果我们依赖io的结果, 异步io和同步阻塞io都是要等到io完成才能继续 ...

  7. PHP日志扩展 SeasLog-1.6.8, 性能更优

    SeasLog-1.6.8 发布了,性能更优. 改进日志: 1.6.8: 优化内存使用和性能,修复已知Bug. - Fixed issue #97 PHP5.* Cached Block. - Fix ...

  8. 能让你成为更优秀程序员的10个C语言资源

    能让你成为更优秀程序员的10个C语言资源 本文由 伯乐在线 - archychu 翻译自 mycplus.欢迎加入 技术翻译小组.转载请参见文章末尾处的要求. 一些人觉得编程无聊,一些人觉得它很好玩. ...

  9. graphicview和widgets没本质区别。它只是更轻量级,更灵活,性能更高的widgets

    graphicview和widgets没本质区别.它只是更轻量级,更灵活,性能更高的widgets.核心就是把widgets变成了更轻量级的graphicitem,把QWidget的各种事件转换成了g ...

随机推荐

  1. 05 C语言的数据类型

    C语言的数据类型 在C 中,数据类型是用来声明不同类型的变量或函数的一个广泛的概念.变量的数据类型决定了变量存储占用的空间大小,以及如何去解释存储的位模式. C 中的数据类型可分为以下几大类: 序号 ...

  2. 微服务 | Spring Cloud(一):从单体SSM 到 Spring Cloud

    系列文章目录 微服务 | Spring Cloud(一):从单体SSM 到 Spring Cloud 目录 系列文章目录 前言 单体式架构 微服务架构 优点 缺点 服务发现与弹性扩展 参考 前言 在微 ...

  3. vue : 无法加载文件 C:\Users\Lenovo\AppData\Roaming\npm\vue.ps1,因为在此系统上禁止运行脚本。

    第一步:用管理员身份打开 第二步:执行:set-ExecutionPolicy RemoteSigned 选择Y或A,回车

  4. Linux init 详解(0,1,2,3,4,5,6)

    一.什么是 init init是Linux系统操作中不可缺少的程序之一. 所谓的init进程,它是一个由内核启动的用户级进程. 内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数 ...

  5. RHSA-2017:2930-重要: 内核 安全和BUG修复更新(需要重启、存在EXP、本地提权、代码执行)

    [root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) 修复命令: 使用root账号登陆She ...

  6. ORA-00019: maximum number of session licenses exceeded 超出最大会话许可数

    ORA-00019: maximum number of session licenses exceededORA-00019: 超出最大会话许可数 Cause:       All licenses ...

  7. C# 软件版本号

    如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! ! --------------------------- ...

  8. Swoole实时任务异步调用Demo

    server.php <?php class Server { private $serv; private $logFilePath = "/data/wwwroot/houtai/ ...

  9. CVE-2010-2883-CoolType.dll缓冲区溢出漏洞分析

    前言 此漏洞是根据泉哥的<漏洞战争>来学习分析的,网上已有大量分析文章在此只是做一个独立的分析记录. 复现环境 操作系统 -> Windows XP Sp3 软件版本 -> A ...

  10. Thumbnailator处理图片

    读取源图 of(String... files) of(File... files) of(InputStream... inputStreams) of(URL... urls) 输出文件 toFi ...