What Are C# Attributes?

A guide to attributes in C#, a powerful mechanism for adding declarative metadata to your code. Learn how attributes work and see common examples from data validation to testing frameworks.

When you write C# code, you've likely encountered code in square brackets [] just before a class or method definition. These are called attributes, and they are a powerful way to add declarative information, or metadata, to your code.

Attributes don't change the behavior of your code directly. Instead, they provide extra information about your code that can be queried at runtime by other tools and frameworks.

What Do Attributes Look Like?

An attribute is a class that inherits from System.Attribute. You apply an attribute to a code element by placing its name in square brackets before the element. By convention, attribute class names end with Attribute, but you can omit that suffix when you use it.

For example, the [Obsolete] attribute is used to mark a method as outdated.

// The ObsoleteAttribute class is being used here
[Obsolete("This method is outdated. Use NewMethod instead.")]
public void OldMethod()
{
    // ...
}

When another developer tries to use OldMethod, the compiler will see the [Obsolete] attribute and generate a warning, displaying the message you provided.

How Do Attributes Work?

Attributes are essentially a way of attaching extra information to your code's assemblies. This information can then be read at runtime using a technique called reflection.

A framework can use reflection to inspect your code, look for specific attributes, and then change its behavior based on the attributes it finds.

Common Use Cases for Attributes

Attributes are used extensively throughout the .NET framework and many third-party libraries.

1. Data Validation (ASP.NET Core)

In ASP.NET Core, you can use validation attributes from the System.ComponentModel.DataAnnotations namespace to declare rules for your model properties.

public class RegisterModel
{
    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    [StringLength(100, MinimumLength = 8)]
    public string Password { get; set; }
}

When ASP.NET Core receives a request to create a RegisterModel, its model binding system uses reflection to find these attributes and automatically validates the incoming data against them.

2. API Behavior (ASP.NET Core)

Attributes are used to define the behavior of API controllers.

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet("{id}")]
    public Product GetById(int id)
    {
        // ...
    }
}
  • [ApiController] enables a set of features for API development.
  • [Route] defines the URL template for the controller.
  • [HttpGet] marks a method as an action that handles HTTP GET requests.

3. Testing (xUnit)

Testing frameworks like xUnit use attributes to identify test methods.

public class MyTests
{
    [Fact]
    public void MyTest()
    {
        // ...
    }

    [Theory]
    [InlineData(1)]
    [InlineData(2)]
    public void MyTheoryTest(int value)
    {
        // ...
    }
}

The xUnit test runner scans your assembly for methods marked with [Fact] or [Theory] and executes them as tests.

Creating Your Own Custom Attributes

You can also create your own attributes by creating a class that inherits from System.Attribute.

// Define a custom attribute
public class AuthorAttribute : Attribute
{
    public string Name { get; }

    public AuthorAttribute(string name)
    {
        Name = name;
    }
}

// Apply the custom attribute
[Author("Eric Wilson")]
public class MyAwesomeClass
{
    // ...
}

You could then write a tool that uses reflection to scan your assemblies and generate a report of all the authors for each class.

Conclusion

Attributes are a powerful and pervasive feature in the .NET ecosystem. They provide a clean, declarative way to add metadata to your code, enabling frameworks and tools to do amazing things. By understanding how attributes work, you can gain a deeper insight into how your favorite frameworks operate and even start to build your own tools that leverage this powerful mechanism.