我今天注意到我的intellisense中出现了一些新属性,用于我的.NET 4.5项目的System.Type
对象。其中一个名为CustomAttributes
。
我对此很感兴趣,因为我之前已经知道GetCustomAttributes
是最昂贵的反射调用之一(当然除了DynamicInvoke
之外)。据我所知,每次调用GetCustomAttributes
都会导致调用属性的构造函数(从而调用内存)。我经常使用单独缓存自定义属性来避免在处理大量类型等时出现性能瓶颈。
所以,我写了一个测试,看看CustomAttributes
是否比GetCustomAttributes
更高效:
static void Main(string[] args)
{
var sw = Stopwatch.StartNew();
Debug.WriteLine(typeof(Attributed).GetType());
for (int i = 0; i < 10000; i++)
{
var attrs = typeof(Attributed)
.CustomAttributes
.Select(a => a.AttributeType)
.ToList();
}
sw.Stop();
Debug.WriteLine("Using .NET 4.5 CustomAttributes property: {0}", sw.Elapsed);
sw = Stopwatch.StartNew();
for (int i = 0; i < 10000; i++)
{
var attrs = typeof(Attributed)
.GetCustomAttributes(true)
.Select(a => a.GetType())
.ToList();
}
sw.Stop();
Debug.WriteLine("Using GetCustomAttributes method: {0}", sw.Elapsed);
}
使用一些测试类:
[Dummy]
[Dummy]
[Dummy]
[Dummy]
[Dummy]
[Dummy]
class Attributed
{
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true)]
class DummyAttribute : Attribute
{
public DummyAttribute()
{
}
}
结果令人惊讶:
System.RuntimeType
Using .NET 4.5 CustomAttributes property: 00:00:00.1351259
Using GetCustomAttributes method: 00:00:00.0803161
新的CustomAttributes
属性实际上比现有的GetCustomAttributes
方法慢!
进一步调试,我发现没有调用属性构造函数来迭代CustomAttributes
(我预期它,因为它看起来只是在读取元数据)。但不知何故,它比调用构造函数的GetCustomAttributes
慢。
就我个人而言,我认为使用新属性更具可读性,但成本却低了1.5倍。
那么,使用CustomAttributes
代替GetCustomAttributes()
有什么优势呢?
我假设我们只是检查clas上是否存在某种类型的属性...不使用属性实例上的方法或属性。
答案 0 :(得分:12)
你正在制造传统的基准测试错误,这使得许多.NET程序员认为Reflection很慢。比实际更慢。反思是非常懒惰的,当你不使用它时,你不会为此付出代价。这使您的第一次测量包括将元数据页面错误输入RAM并设置类型信息反射缓存的所有成本。该成本未包含在第二次测量中,使得GetCustomAttributes()看起来比实际更好。
始终在基准代码周围加一个循环,运行10次。您现在可以看到CustomAttributes属性实际上 缓慢,我测量它(大致)0.083 vs 0.063秒,慢30%。
需要在.NET 4.5中添加CustomAttributes属性以支持WinRT的语言投影。您不能在Store,Phone或PCL项目中使用GetCustomAttributes()。在WinRT中反射非常不同,这是基于COM的api的不可避免的副作用。实现代码足以让任何人的眼睛流血,但大致的概述是该属性是用C#实现的,并且该方法是在CLR中实现的。 C#代码需要做更多工作来处理语言投影细节,因此不可避免地会变慢。
因此,只需继续使用GetCustomAttributes(),必要时使用该属性。 30%的速度差异并不是影响风格和可读性的重要原因,应用您的常识。