I noticed today that some new properties had appeared in my intellisense on the System.Type
object for my .NET 4.5 projects. Among these was one called CustomAttributes
.
I was intrigued by this since I previously had understood that GetCustomAttributes
was one of the most expensive reflection calls (DynamicInvoke
and the like aside, of course). As I understand it, every call to GetCustomAttributes
results in calling the constructors for the attributes (and thus a memory allocation). I've often resorted to caching the custom attributes separately to avoid performance bottlenecks when processing large numbers of types and such.
So, I wrote up a test to see if CustomAttributes
was any more performant than 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);
}
With some test classes:
[Dummy]
[Dummy]
[Dummy]
[Dummy]
[Dummy]
[Dummy]
class Attributed
{
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true)]
class DummyAttribute : Attribute
{
public DummyAttribute()
{
}
}
The results were surprising:
System.RuntimeType
Using .NET 4.5 CustomAttributes property: 00:00:00.1351259
Using GetCustomAttributes method: 00:00:00.0803161
The new CustomAttributes
property was actually slower than the existing GetCustomAttributes
method!
Debugging further, I discovered that the attribute constructors were not called for iterating CustomAttributes
(which I expected since it looks like it is just reading the metadata). Yet somehow, it was slower than GetCustomAttributes
which calls constructors.
Personally I think it is more readable to use the new property, but the cost is 1.5x-ish slower performance.
So, what advantage is there, if any, of using CustomAttributes
instead of GetCustomAttributes()
?
I'm assuming the situation where we are simply checking to see if an attribute of some type exists on the clas...not using methods or properties on the instance of the attribute.
Attributes are metadata extensions that give additional information to the compiler about the elements in the program code at runtime. Attributes are used to impose conditions or to increase the efficiency of a piece of code.
Attributes provide a way of associating information with code in a declarative way. They can also provide a reusable element that can be applied to a variety of targets. Consider the [Obsolete] attribute. It can be applied to classes, structs, methods, constructors, and more.
Retrieving a custom attribute is a simple process. First, declare an instance of the attribute you want to retrieve. Then, use the Attribute. GetCustomAttribute method to initialize the new attribute to the value of the attribute you want to retrieve.
By using reflection, you can retrieve the information that was defined with custom attributes. The key method is GetCustomAttributes , which returns an array of objects that are the run-time equivalents of the source code attributes.
You are making a traditional benchmarking mistake, one that makes many .NET programmers think that Reflection is slow. Slower than it actually is. Reflection is very lazy, you don't pay for it when you don't use it. Which makes your first measurement include all the cost of page-faulting the metadata into RAM and setup the type info reflection cache. That cost is not included in the second measurement, making GetCustomAttributes() look better than it actually is.
Always include a loop around the benchmark code, run it 10 times. You'll now see that the CustomAttributes property isn't actually that slow, I measure it at (roughly) 0.083 vs 0.063 seconds, ~30% slower.
The CustomAttributes property needed to be added in .NET 4.5 to support the language projection for WinRT. You cannot use GetCustomAttributes() in a Store, Phone or PCL project. Reflection is very different in WinRT, an inevitable side-effect of it being a COM based api. Implementation code is enough to make anyone's eyes bleed but the broad outline is that the property is implemented in C# and the method is implemented in the CLR. The C# code needs to do more work to handle the language projection details so is inevitably slower.
So just keep using GetCustomAttributes(), use the property when you have to. A 30% speed difference isn't otherwise a drastic reason to compromise style and readability, apply your common sense.
An important difference seems to be that CustomAttributes returns IEnumerable<CustomAttributeData> while GetCustomAttributes returns object[] containing instances derived from Attribute.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With