Overview
As part of C#, attributes allow developers to add metadata to their code. It can be used for a variety of purposes, including controlling serialization, providing runtime hints, or creating documentation. A number of improvements have been made to the way attributes and metadata can be utilized in C# 12, resulting in more maintainable and self-documenting code.
This article examines the advanced use of attributes in C# 12, including the new features introduced in this version, as well as practical examples and best practices.
How do Attributes work in C# 12?
The Attribute Parameters
As a result, attributes can now have parameters that are not just primitive types or strings. It is now possible to use read-only structs, enums, and other complex types as parameters. This allows you to create attributes that are more expressive and type-safe.
Attributes specific to a target
Attributes can now be more specific about where they can be applied, allowing you to define constraints based on the target, whether it be classes, methods, properties, or assemblies.
Enhancing the ability to reflect
With C# 12, reflection support for attributes has been improved, making it easier to retrieve attribute data at runtime, especially for custom attributes.
Attributes with nullable reference types
It is now possible to define attributes with nullable reference types, allowing for more precise definitions and eliminating null-related errors.
The creation of custom attributes
We can illustrate these new features by creating a custom attribute.
Defining a Custom Attribute as an example
using System.Reflection;
namespace CSharp12.AttributesAndMetadata;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false)]
public class DeveloperInfoAttribute : Attribute
{
public string DeveloperName { get; }
public string Version { get; }
public string? Notes { get; }
public DeveloperInfoAttribute(string developerName, string version, string? notes = null)
{
DeveloperName = developerName;
Version = version;
Notes = notes;
}
public static void DisplayDeveloperInfo(MemberInfo member)
{
var attribute = member.GetCustomAttribute<DeveloperInfoAttribute>();
if (attribute != null)
{
Console.WriteLine($"Member: {member.Name}");
Console.WriteLine($"Developer: {attribute.DeveloperName}");
Console.WriteLine($"Version: {attribute.Version}");
Console.WriteLine($"Notes: {attribute.Notes}");
Console.WriteLine();
}
else
{
Console.WriteLine($"No DeveloperInfo attribute found on {member.Name}.");
}
}
}
Here, we define a DeveloperInfoAttribute that can be applied to classes and methods. It includes three parameters: DeveloperName, Version, and Notes.
Applying the Attribute
Let's see how our custom attribute can be applied:
namespace CSharp12.AttributesAndMetadata;
[DeveloperInfo("Ziggy Rafiq", "0.0.1", "Initial version")]
public class ExampleClass
{
[DeveloperInfo("Ziggy Rafiq", "0.0.2", "Fixed minor bugs")]
public void ExampleMethod()
{
Console.WriteLine("Executing ExampleMethod.");
}
}
The DeveloperInfoAttribute is applied to both a class and a method here in order to provide relevant metadata.
Attribute data retrieval at runtime
In C# 12, you can retrieve attributes using reflection. Let's create a method that displays the attributes of the SampleClass and its methods.

Join the conversation! Your thoughts help the community grow.