News
C# 11 Features Now Previewing in Visual Studio: Generic Attributes and More
A new "What's new in C# 11" post explains new features available in preview with the latest tooling bits: NET 6.0.200 SDK or Visual Studio 2022 v17.1.
First on tap is generic attributes support, or the ability to create a generic class based on System.Attribute
. The Attribute class provides a way of associating information with code in a declarative way, such that an ObsoleteAttribute
indicates code that is obsolete and shouldn't be used anymore, signaling the compiler to look for instances of the attribute and do something corrective in response.
Some C# 10 Microsoft documentation for generic attributes (support was postponed to C# 11) explains the motivation: "Currently attribute authors can take a System.Type
as a parameter and have users pass a typeof
expression to provide the attribute with types that it needs. However, outside of analyzers, there's no way for an attribute author to constrain what types are allowed to be passed to an attribute via typeof
. If attributes could be generic, then attribute authors could use the existing system of type parameter constraints to express the requirements for the types they take as input."
As the graphic below shows, support for generic attributes is but one of many new features planned for C#:
Generic attribute support was the answer C# expert Jason Bock provided when asked "What's a C# feature that you wish Microsoft would come out with, but it just hasn't materialized?" in the September 2021 article "Q&A with Jason Bock: What's New in C# 10."
"Generic attributes," Bock replied. "This is a capability that the CLR has had for a long time, but it's never been surfaced in C#. You can define generic attributes in the intermediate language of .NET -- IL -- and consume them in C#, but you can't define them in C# directly. There are cases where I think this feature would be useful, and I'm hoping it makes it into C# at some point."
His wishes have come true in Visual Studio 17.1, where a developer need only set <LangVersion>
to "preview" to enable preview features. Among those, "Allow Generic Attributes" has been a long time coming, in the works for at least five years.
New "What's new in C# 11" documentation just published March 11 provides more details on its impending manifestation.
"You can declare a generic class whose base class is System.Attribute. This provides a more convenient syntax for attributes that require a System.Type parameter. Previously, you'd need to create an attribute that takes a Type
as its constructor parameter:"
// Before C# 11:
public class TypeAttribute : Attribute
{
public TypeAttribute(Type t) => ParamType = t;
public Type ParamType { get; }
}
After using the tyepof
operator to apply the attribute, a developer can create a generic attribute and specify the type parameter to use the new feature. However, certain code constructs aren't allowed because when a generic attribute is used, it needs to be fully closed. In other words, it can't contain any type parameters. Here are a couple examples:
-
Example 1:
public class GenericType<T>
{
[GenericAttribute<T>()] // Not allowed! generic attributes must be fully constructed types.
public string Method() => default;
}
-
Example 2:
using System;
using System.Collections.Generic;
public class Attr<T1> : Attribute { }
public class Program<T2>
{
[Attr<T2>] // error
[Attr] // error
void M() { }
}
In addition to explaining the motivation behind the approach, Microsoft also lists a drawback of the scheme: "Removing the restriction, reasoning out the implications, and adding the appropriate tests is work."
An alternative is also listed: "Attribute authors who want users to be able to discover the requirements for the types they provide to attributes need to write analyzers and guide their users to use those analyzers in their builds."
An unresolved question about the scheme reads:
- [x] What does
AllowMultiple = false
mean on a generic attribute? If we have [Attr<string>]
and [Attr<object>]
both used on a symbol, does that mean "multiple" of the attribute are in use?
- For now we are inclined to take the more restrictive route here and consider the attribute class's original definition when deciding whether multiple of it have been applied. In other words,
[Attr<string>]
and [Attr<object>]
applied together is incompatible with AllowMultiple = false
.
The March 11 announcement also notes that type arguments must satisfy the same restrictions as the typeof
operator, and it lists some disallowed metadata annotations.
The post also details static abstract members in interfaces, a runtime preview feature that is also available by this setting: <EnablePreviewFeatures>True</EnablePreviewFeatures>
.
"You can add static abstract members in interfaces to define interfaces that include overloadable operators, other static members, and static properties," Microsoft said. "The primary scenario for this feature is to use mathematical operators in generic types." More on that is available in the tutorial titled "Explore static abstract interface members."
While developer attitudes toward generic attributes seem to be mostly positive, judging by GitHub comments, other C# 11 preview features that Microsoft has discussed drew much developer ire, especially parameter null checking. Read more about that in the article, "Devs Sound Off on C# 11 Preview Features Like Parameter Null Checking."
About the Author
David Ramel is an editor and writer at Converge 360.