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
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.