使用表达式树来提高反射的性能

反射是C#中一种常用的技术,反射提供了动态创建和访问对象的基础,但是反射在带来了极强的灵活性的同时,也带了极大的性能损耗,本文就介绍通过表达式树来提高反射过程中的性能。

反射

关于反射的详细内容,可以查看 MSDN文档的介绍 。这里不做过多说明,下面写一段反射代码。

先定义一个类,在后面反射该类获取 Id 的值。

class Foo{
    public Guid Id { get; set; } = Guid.NewGuid();
}

反射获取属性和值。

// 实例化对象
var foo = new Foo();
// 获取对象的类型
var type = foo.GetType();
// 查找类型中的 “Id” 的属性
var property = type.GetProperty("Id");
// 获取 “Id” 的值
var id = property.GetValue(foo);

表达式树

表达式树是C#一种常用的技术,在很多的框架和库中都有用到,可以查看 MSDN文档介绍 。表达式树最后会参与编译,提高运行时的性能。

修改上面的方法,添加表达式树代码。

var target = Expression.Parameter(typeof(object), "target");
var body = Expression.Convert(Expression.Property(Expression.Convert(target, typeof(Foo)), property), typeof(object));
var getter = Expression.Lambda<Func<object, object>>(body, target).Compile();

上面的代码定义了表达式树,最后生成的表达式类似于 :x => foo.Id 这样一个委托,使用的时候就和委托一样的调用。

// 获取 “Id” 的值
var id = getter.Invoke(foo);

测试

建立一个100000个元素的列表,存放100000个Foo实例,循环获取每一个实例的Id的值,可以看到使用表达式树可以大幅提高性能。

var foos = new List<Foo>();
Stopwatch sw = new Stopwatch();
foos = Enumerable.Repeat(new Foo(),1000000).ToList();
sw.Restart();
for (int i = 0; i < 1000000; i++)
{
    var id = property.GetValue(foos[i]);
}
sw.Stop();

foos = Enumerable.Repeat(new Foo(),1000000).ToList();
sw.Restart();
for (int i = 0; i < 1000000; i++)
{
    var id = getter.Invoke(foos[i]);
}
sw.Stop();

分别测试1000、10000、100000、1000000、10000000个元素的结果如下所示,时间以ms为单位。

1000对象 10000对象 100000对象 1000000对象 10000000对象
反射 0 0 10 110 369
表达式树 0 0 1 40 971

除了取值之外,还可以使用表达式树来赋值,也可以大幅度提高代码运行的性能。后面有时间再补上赋值的比较,

发布时间:2024-01-08
其他阅读

记录中文名WPF应用无法启动

今年开春,突然就收到部分用户反馈软件无法启动的问题,沟通后远程查看发现应用刚启动就直接崩溃了,在Windows的事件查看器可以看到应用的崩溃日志,发现是 ucrtbase.dll 模块崩溃,错误代码 0x0000409

查看原文

扩展Serilog实现日志推送平台

最近在完成一个服务管理平台,提供可视化管理车间控制服务,包括服务的启停,日志的查看。在各服务中使用 Serilog 对日志进行记录,推送到服务管理平台,再进行统一分发,各客户端同步查看服务运行日志。

查看原文

Fetch发送请求

fetch 是 javascript 中一个新的 api,用于访问和控制 HTTP 的请求和响应等,不再需要使用传统的 XMLHttoRequest

查看原文

Js使用原型链对对象进行扩展

在C#的扩展方法中,我们了解到了一种不需要修改源对象定义即可为对象添加新的行为的方法,在JavaScript中,我们通过原型链也可以实现类似的效果,为对象添加新的行为。需要一定的Js原型链基础。

查看原文

使用表达式树来提高反射的性能

反射是C#中一种常用的技术,反射提供了动态创建和访问对象的基础,但是反射在带来了极强的灵活性的同时,也带了极大的性能损耗,本文就介绍通过表达式树来提高反射过程中的性能。

查看原文