Generic attributes with C#11

Starting with C# 11 attributes can now contain generic parameters

Home DailyDrop

Daily Knowledge Drop

Coming in C# 11 (later this year with .NET 7) is the generic attributes feature - the ability to define an attribute which takes a generic parameter. This is a more convenient style for attributes which require a Type parameter.

Generic attribute code samples below were written using the .NET 7 preview release.


Pre C# 11 - Type parameter

Sometimes an attribute needs to take a Type parameter - currently (using any version prior to C# 11) the only way to do this is passing a Type parameter to the constructor.

[System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public class TypeAttribute : Attribute
{
    readonly Type _classType;

    public TypeAttribute(Type classType)
    {
        if(classType is not IMarkerInterface)
        {
             throw new Exception($"Parameter '{classType}'" +
                $" must implement `IMarkerInterface`");
        }

        _classType = classType;
    }

    public Type ClassType
    {
        get { return _classType; }
    }
}

A drawback of this approach is that if there are any constraints on the type of Type then a check needs to explicitly be done in the constructor - as is done above, ensuring that the type implements IMarkerInterface. However this check is only done at runtime, quite late in the development loop.

Usage of the above attribute:

[TypeParam(typeof(ImplementationType))]
public class UsingTypeAttribute
{
}

C# 11 - Generic attribute

C# 11 introduces generic attributes - which use the same syntax as generic classes or methods. Below is the same attribute as above, but implemented using generics:

[System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public class GenericTypeAttribute<T> : Attribute where T : IMarkerInterface
{
    public GenericTypeAttribute()
    {
    }

    public Type ClassType
    {
        get { return typeof(T); }
    }
}
``

As one can see, the code is a lot cleaner, with the type of `Type` being constrained as part of the generics - no need to manually check the type in the constructor. The check is also automatically performed at compile time so any issues with the `Type` are picked up earlier.

Usage of the above attribute is also cleaner:

``` csharp
[GenericType<ImplementationType>]
public class UsingGenericAttribute
{
}

Notes

While this may not be something used every day by everyone, for those which do use it, it will be an incredibly useful upgrade - bringing more standardization across the various parts of the C# language.


References

Generic attributes

Daily Drop 85: 31-05-2022

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net attribute generic