It's been discussed before on Stack Overflow that we should prefer attributes to marker interfaces (interfaces without any members). Interface Design article on MSDN asserts this recommendation too:
Avoid using marker interfaces (interfaces with no members).
Custom attributes provide a way to mark a type. For more information about custom attributes, see Writing Custom Attributes. Custom attributes are preferred when you can defer checking for the attribute until the code is executing. If your scenario requires compile-time checking, you cannot comply with this guideline.
There's even an FxCop rule to enforce this recommendation:
Avoid empty interfaces
Interfaces define members that provide a behavior or usage contract. The functionality described by the interface can be adopted by any type, regardless of where the type appears in the inheritance hierarchy. A type implements an interface by providing implementations for the interface's members. An empty interface does not define any members, and as such, does not define a contract that can be implemented.
If your design includes empty interfaces that types are expected to implement, you are probably using an interface as a marker, or a way of identifying a group of types. If this identification will occur at runtime, the correct way to accomplish this is to use a custom attribute. Use the presence or absence of the attribute, or the attribute's properties, to identify the target types. If the identification must occur at compile time, then using an empty interface is acceptable.
The article states only one reason that you might ignore the warning: when you need compile time identification for types. (This is consistent with the Interface Design article).
It is safe to exclude a warning from this rule if the interface is used to identify a set of types at compile-time.
Here comes the actual question: Microsoft didn't conform to their own recommendation in the design of the Framework Class Library (at least in a couple cases): IRequiresSessionState interface and IReadOnlySessionState interface. These interfaces are used by the ASP.NET framework to check whether it should enable session state for a specific handler or not. Obviously, it's not used for compile time identification of types. Why they didn't do that? I can think of two potential reasons:
Micro-optimization: Checking whether an object implements an interface (
obj is IReadOnlySessionState
) is faster than using reflection to check for an attribute (type.IsDefined(typeof(SessionStateAttribute), true)
). The difference is negligible most of the time but it might actually matter for a performance-critical code path in the ASP.NET runtime. However, there are workarounds they could have used like caching the result for each handler type. The interesting thing is that ASMX Web services (which are subject to similar performance characteristics) actually use theEnableSession
property of theWebMethod
attribute for this purpose.Implementing interfaces are potentially more likely to be supported than decorating types with attributes by third-party .NET languages. Since ASP.NET is designed to be language agnostic, and ASP.NET generates code for types (possibly in a third-party language with the help of CodeDom) that implement the said interfaces based on the
EnableSessionState
attribute of the<%@ Page %>
directive, it might make more sense to use interfaces instead of attributes.
What are the persuasive reasons to use marker interfaces instead of attributes?
Is this simply a (premature?) optimization or a tiny mistake in the framework design? (Do they think reflection is a "big monster with red eyes"?) Thoughts?