I, for one, believe that attributes are far the best way to mark a class instead of using an empty marker interface. Why? Well, there are several good reasons to use attributes over interfaces, especially when it comes to inheritance. That aside, attributes are also a lot more flexible than interfaces.
So why don’t people use attributes more often? The most common complaint is that interfaces are easier to use and check for in code (I.e. interfaces requires less code). But I think this is mainly because people don’t know where to look for help in the framework. So I’ve devised 30 extension methods that will make your work with attributes a little bit easier and strongly typed.
public static class AttributeExtensions { // Attribute.IsDefined shortcuts public static bool HasAttribute<T>(this object element) where T : Attribute { return Attribute.IsDefined(element.GetType(), typeof(T)); } public static bool HasAttribute<T>(this object element, bool inherit) where T : Attribute { return Attribute.IsDefined(element.GetType(), typeof(T), inherit); } public static bool HasAttribute<T>(this Assembly element) where T : Attribute { return Attribute.IsDefined(element, typeof(T)); } public static bool HasAttribute<T>(this Assembly element, bool inherit) where T : Attribute { return Attribute.IsDefined(element, typeof(T), inherit); } public static bool HasAttribute<T>(this MemberInfo element) where T : Attribute { return Attribute.IsDefined(element, typeof(T)); } public static bool HasAttribute<T>(this MemberInfo element, bool inherit) where T : Attribute { return Attribute.IsDefined(element, typeof(T), inherit); } public static bool HasAttribute<T>(this Module element) where T : Attribute { return Attribute.IsDefined(element, typeof(T)); } public static bool HasAttribute<T>(this Module element, bool inherit) where T : Attribute { return Attribute.IsDefined(element, typeof(T), inherit); } public static bool HasAttribute<T>(this ParameterInfo element) where T : Attribute { return Attribute.IsDefined(element, typeof(T)); } public static bool HasAttribute<T>(this ParameterInfo element, bool inherit) where T : Attribute { return Attribute.IsDefined(element, typeof(T), inherit); } // Attribute.GetCustomAttribute shotcuts public static T GetAttribute<T>(this object element) where T : Attribute { return Attribute.GetCustomAttribute(element.GetType(), typeof(T)) as T; } public static T GetAttribute<T>(this object element, bool inherit) where T : Attribute { return Attribute.GetCustomAttribute(element.GetType(), typeof(T), inherit) as T; } public static T GetAttribute<T>(this Assembly element) where T : Attribute { return Attribute.GetCustomAttribute(element, typeof(T)) as T; } public static T GetAttribute<T>(this Assembly element, bool inherit) where T : Attribute { return Attribute.GetCustomAttribute(element, typeof(T), inherit) as T; } public static T GetAttribute<T>(this MemberInfo element) where T : Attribute { return Attribute.GetCustomAttribute(element, typeof(T)) as T; } public static T GetAttribute<T>(this MemberInfo element, bool inherit) where T : Attribute { return Attribute.GetCustomAttribute(element, typeof(T), inherit) as T; } public static T GetAttribute<T>(this Module element) where T : Attribute { return Attribute.GetCustomAttribute(element, typeof(T)) as T; } public static T GetAttribute<T>(this Module element, bool inherit) where T : Attribute { return Attribute.GetCustomAttribute(element, typeof(T), inherit) as T; } public static T GetAttribute<T>(this ParameterInfo element) where T : Attribute { return Attribute.GetCustomAttribute(element, typeof(T)) as T; } public static T GetAttribute<T>(this ParameterInfo element, bool inherit) where T : Attribute { return Attribute.GetCustomAttribute(element, typeof(T), inherit) as T; } // Attribute.GetCustomAttributes shortcuts public static T[] GetAttributes<T>(this object element) where T : Attribute { return Attribute.GetCustomAttributes(element.GetType(), typeof(T)) as T[]; } public static T[] GetAttributes<T>(this object element, bool inherit) where T : Attribute { return Attribute.GetCustomAttributes(element.GetType(), typeof(T), inherit) as T[]; } public static T[] GetAttributes<T>(this Assembly element) where T : Attribute { return Attribute.GetCustomAttributes(element, typeof(T)) as T[]; } public static T[] GetAttributes<T>(this Assembly element, bool inherit) where T : Attribute { return Attribute.GetCustomAttributes(element, typeof(T), inherit) as T[]; } public static T[] GetAttributes<T>(this MemberInfo element) where T : Attribute { return Attribute.GetCustomAttributes(element, typeof(T)) as T[]; } public static T[] GetAttributes<T>(this MemberInfo element, bool inherit) where T : Attribute { return Attribute.GetCustomAttributes(element, typeof(T), inherit) as T[]; } public static T[] GetAttributes<T>(this Module element) where T : Attribute { return Attribute.GetCustomAttributes(element, typeof(T)) as T[]; } public static T[] GetAttributes<T>(this Module element, bool inherit) where T : Attribute { return Attribute.GetCustomAttributes(element, typeof(T), inherit) as T[]; } public static T[] GetAttributes<T>(this ParameterInfo element) where T : Attribute { return Attribute.GetCustomAttributes(element, typeof(T)) as T[]; } public static T[] GetAttributes<T>(this ParameterInfo element, bool inherit) where T : Attribute { return Attribute.GetCustomAttributes(element, typeof(T), inherit) as T[]; } }
Now you can check for the existence of an attribute like this:
var instance = new SomeClass(); // How to check for attributes using the extension methods. bool hasMarkerAttribute = instance.HasAttribute<MyMarkerAttribute>(); // How to check for marker interface using unfair compiler sugar. ;) bool hasMarkerInterface = instance is IMyMarkerInterface; // Not that much shorter, right?
Well, I hope someone can use this… Any thoughts or criticisms for the code will be greatly appreciated. Otherwise, enjoy! ;)

4 comments:
Nice class! Have you considered or tested the performance difference of the marker interface check vs checking for attributes using your code?
Performance of attributes vs. interfaces is very different and attribute comes out losing. In the tests I did, checking attributes were significantly slower than checking interfaces, sometimes up to 1000-2000 times slower!
But don't be too scared. For individual checks we are still speaking about 0.00002 secs. per attribute check, so it is not hurting your performance in any noticeable way as long as you aren't doing several thousand checks per second.
The thing to do is to judge it on a case by case basis and weigh the pros and cons whenever you need to employ a marker interface or attribute. Interfaces may be fast but has less flexibility than attributes.
And with that, I believe you've addressed the two most significant concerns of the subject matter. Thank you!
You may use this mixin :)
public static bool IsAttributeDefined<T>(this ICustomAttributeProvider provider, bool inherit = true)
where T : Attribute
{
return provider.IsDefined(typeof(T), inherit);
}
public static T[] GetAttributes<T>(this ICustomAttributeProvider provider, bool inherit = true)
where T : Attribute
{
return provider.GetCustomAttributes(typeof(T), inherit) as T[];
}
public static T GetFirstAttribute<T>(this ICustomAttributeProvider provider, inherit = true)
where T : Attribute
{
return provider.GetAttributes<T>(inherit).FirstOrDefault();
}
}
P.S. some C# 4.0 code :)
Post a Comment