Dustin Horne

Developing for fun...

Generic Attributes in C#

First I'd like to note a correction as this original post was unintentionally misleading.  The following works with Mono but will not work with the full fledged .NET Framework.

This afternoon while doing some related research I realized that I had been doing something for awhile that appears to be somewhat of a unicorn in the C# community:  using generic attributes.  Upon further research I saw a lot of information on creating generic attributes that ranged from "you can't" to "here's how you create a custom type descriptor and dynamically inject the attribute".  As I have been doing it for awhile a much easier way, I somehow was never aware that it was a problem for some, so here is how you do it.

First, what won't work.  Consider the following:

public class SomeFancyAttribute<T> : Attribute
{
   //..Stuff here
}

This actually won't work.  .NET does not allow you to create a generic attribute that inherits from Attribute.  Why not?  Well, personally I have no idea.  I have read a lot of interesting theories, many of which talked about compile time vs runtime and needing to know the types.  However, unless you're dynamically creating and injecting those attributes, you are specifying the types so these are technically known at compile time.  Regardless of the reason, the simple solution is to place another attribute class in between which actually works perfectly (even as far back as .NET 3.5 and Mono).  So the following works perfectly:

 

public abstract class GenericBaseAttribute : Attribute
{
}


public class SomeFancyAttribute<T> : GenericBaseAttribute
{
   //..Fancy stuff here
}

And now you can apply your attribute like so:

 

[SomeFancyAttribute<string>]
public class MyFancyClass
{
  //..fancy class logic
}

And that's all there is to it. Most likely you're going to want to add some generic constraints to your attribute definition because you're still going to be using it for something specific, but it's all possible and without the complexities of adding a custom type descriptor or any other kind of hackery.