繁体   English   中英

.NET 反射在 .NET 4.7.x 中比在 3.5 中慢 3 倍

[英].NET reflection 3 times slower in .NET 4.7.x than in 3.5

我有一个从 .NET 3.5 升级到 .NET 4.7.2 的应用程序。 唯一的问题确实是我们使用反射的部分代码的性能。 整个情况在我上传到 Gist 的一个简单示例中得到了最好的解释: https ://gist.github.com/vkocjancic/3e8a6b3496c412a75b1c85a1d2ba1111

基本上,我们有一个 POCO 类,如果未为不可空类型的属性设置值,则属性方法会抛出异常。

[编辑]:

  1. 是的,我知道那是不正确的或不适合使用的模式,但是,该应用程序是从 .NET 1.1 开始的。

  2. 是的,它早就应该修好了。 事实并非如此。

然后使用反射获取 POCO 类实例的属性名称和值,并将其填充到 DataTable。

示例和现实生活中的项目源代码完全相同。 唯一的区别是,在一种情况下,它是使用 .NET 3.5 编译的,而在第二种情况下,它是使用 .NET 4.7.2 编译的。

这是 10 次调用的平均耗时(以毫秒为单位):

.NET 3.5      ->  231.1 ms
.NET 4.7.2    ->  713.5 ms
.NET Core 2.2 -> 1013.2 ms

谁能详细说明为什么反射在 .NET 4.7.2 中比在 .NET 3.5 中慢 3 倍,以及如何解决这个问题。 只有在未设置属性并抛出异常时才会发生滞后。 如果您填充属性值,则性能没有差异。

如果我在调试器中运行示例,.NET 3.5 构建永远不会触发 MissingFieldException。 使用 .NET 4.7.2 构建会触发每个异常。

[编辑]

正如@bevan 所提到的,减速实际上发生在切换到 .NET 4.0 时。 > 此外,问题归结为在 .NET 3.5 中抛出和处理异常的速度比在 .NET 4.0 中快 3 倍

正如我在评论中提到的,如果您在访问属性之前调用IsPROP_NUMERIC_ANull函数,它不会再抛出任何异常并且速度非常快。

foreach (var myObject in objects)
{
    var row = table.NewRow();

    // TODO implement some caching: dont call GetProperties(), GetMethod(), for every object
    var type = myObject.GetType();
    var properties = type.GetProperties();

    foreach (var info in properties)
    {
        try
        {
            // call the IsNullMethod for the property, eg "IsPROP_NUMERIC_ANull"
            var isNullMethodName = $"Is{info.Name}Null";
            var isNullMethod = type.GetMethod(isNullMethodName, BindingFlags.Instance | BindingFlags.Public);

            if (isNullMethod != null)
            {
                var fldIsNull = (bool)isNullMethod.Invoke(myObject, new object[] { });
                if (!fldIsNull)
                    row[info.Name] = info.GetValue(myObject, null);
            } else
            {
                // isNullMethod doesn't exist
                row[info.Name] = info.GetValue(myObject, null);
            }
        }
        catch
        {
            // do nothing
        }
    }
    table.Rows.Add(row);
}

总运行时间为3 ms ,而之前为 19500 毫秒。

如果您可以重新设计它,我会使用像 Marc Gravell 提议的缓存委托。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM