Vla*_*cic 6 c# reflection exception
我有一个应用程序,我们将其从 .NET 3.5 升级到 .NET 4.7.2。唯一的问题确实是我们使用反射的部分代码的性能。在我上传到 Gist 的一个简单示例中最好地解释了整个情况:https : //gist.github.com/vkocjancic/3e8a6b3496c412a75b1c85a1d2ba1111
基本上,我们有一个 POCO 类,如果未为不可空类型的属性设置值,则该类属性方法会抛出异常。
[编辑]:
是的,我知道这是不正确的或不好使用的模式,但是,该应用程序是从 .NET 1.1 开始的。
是的,早就该修好了。不是。
然后使用反射来获取 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
Run Code Online (Sandbox Code Playgroud)
谁能详细说明为什么 .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);
}
Run Code Online (Sandbox Code Playgroud)
总运行时间3 ms与之前的 19500 毫秒相比。
如果你可以重新设计这个,我会使用像 Marc Gravell提议的缓存代表。