How to Create Your Own Custom Attributes in C#
Aug 15, 2019 • 8 Minute Read
Introduction
Attributes are a great way to add metadata or information in a declaritive way to your code. In .NET MVC projects with C#, you can find attributes used to add validation to models.
Required]
[StringLength(50
Attributes help define routes, HTTP verbs, and permissions.
Route("Articles")]
[Authorize(Policy = "Editor")]
public class NewsArticleController : Controller
{
[Route("")]
[Route("List")]
public IActionResult Index() { ... }
[HttpPost("article/{id}")]
public IActionResult Edit(int id) { ... }
}
How to Create a Simple Attribute
In Visual Studio the quickest and easiest way to get started with Attributes is with the Attribute Snippet. You can type Attribute and press Tab to have Visual Studio generate a sample Attribute snippet. That Attribute snippet generates the following:
System.AttributeUsage(AttributeTargets.All
This generates a new class that inherits from the Attribute class. It is not required that the class ends with "Attribute" but it is a convention to help others understand your code.
An important thing to note is that the class has an attribute itself that asks three questions.
- Attribute Targets - What type of elements can this attribute be applied to? AttributeTargets is an enum that lists the possible targets available.
- Inherited - If you apply this attribute to a class named AnimalClass and you inherit another class named DogClass from AnimalClass, should this attribute be inherited as well?
- Allow Multiple - Can multiple instances of this attribute be set on a single element?
An Attribute class can accept required constructor parameters, optional constructor parameters, and multiple constructor overloads, just like most any other class in C#.
Using a similar example to the one in Jason Roberts' C# Attributes: Power and Flexibility for Your Code Pluralsight course, we can create an attribute that changes the color of a property when displayed in a console app.
We will modify the original snippet generated by Visual Studio to create a Color Attribute class.
AttributeUsage(AttributeTargets.Property
This allows someone to use [Color] or [Color(ConsoleColor.Red)] on a property. It sets the default color to be Cyan if no color is added to the attribute when used.
A common thing that trips people up with custom attributes is that they are a two step process. The above code only allows us to set the attribute on a property. We now need to add logic elsewhere in our application to use our new attribute.
// First apply our new attributes to properties in a class
public class Dog
{
[Color(ConsoleColor.Red)]
public string Name { get; set; }
[Color]
public string Breed { get; set; }
public int Age { get; set; }
}
// Next create a class to use those properties
public static class DogConsoleWriter
{
public static void Line(Dog dog)
{
var defaultColor = Console.ForegroundColor;
Console.Write("Name: ");
// Here the console foreground is set to either the attribute color or a default color
Console.ForegroundColor = GetPropertyColor(nameof(Dog.Name)) ?? defaultColor; ;
Console.Write(dog.Name);
Console.ForegroundColor = defaultColor;
Console.WriteLine();
Console.Write("Breed: ");
Console.ForegroundColor = GetPropertyColor(nameof(Dog.Breed)) ?? defaultColor;
Console.Write(dog.Breed);
Console.ForegroundColor = defaultColor;
Console.WriteLine();
Console.Write("Age: ");
Console.ForegroundColor = GetPropertyColor(nameof(Dog.Age)) ?? defaultColor;
Console.Write(dog.Age);
Console.ForegroundColor = defaultColor;
Console.WriteLine();
}
// Here is the most important part
private static ConsoleColor? GetPropertyColor(string propertyName)
{
// This uses C#'s reflection to get the attribute if one exists
PropertyInfo propertyInfo = typeof(Dog).GetProperty(propertyName);
ColorAttribute colorAttribute = (ColorAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(ColorAttribute));
// If colorAttribute is not null, than a color attribute exists
if(colorAttribute != null)
{
return colorAttribute.Color;
}
return null;
}
}
Now a Console application could use this class in a similar fashion:
DogConsoleWriter.Line(new Dog
{
Name= "Astro",
Breed= "Newfoundland"
});
Let's take a closer look at the GetPropertyColor method where the most important steps are done.
private static ConsoleColor? GetPropertyColor(string propertyName)
{
PropertyInfo propertyInfo = typeof(Dog).GetProperty(propertyName);
ColorAttribute colorAttribute = (ColorAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(ColorAttribute));
if(colorAttribute != null)
{
return colorAttribute.Color;
}
return null;
}
This method accepts a string of the property name GetPropertyColor(string propertyName). The string is passed by using the nameof operator, nameof(Dog.Age), to provide type safety.
The property name is then used in the first line of the method to get the Property Info for the type specified. The type in our case is the Dog type. PropertyInfo propertyInfo = typeof(Dog).GetProperty(propertyName);
Once the PropertyInfo is obtained we can check to see if it has any attributes applied. Since we only care about the ColorAttribute, we specify that type. ColorAttribute colorAttribute = (ColorAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(ColorAttribute));
GetCustomAttribute will return null if it cannot find an attribute.
Where Attributes Can Be Applied
You can add an attribute to any of the following in C#:
- Classes
- Methods
- Enums
- Events
- Fields
- Properties
- Structs
- Parameters
- Constructors
- Delegates
- Interfaces
- Return values
- Assemblies
- Other Attributes too!
Summary
Adding attributes helps others to understand what your code aims to accomplish at a quick glance, without having to understand the logical steps that make it happen.
To learn even more about C# Attributes, check out the full course C# Attributes: Power and Flexibility for Your Code by Jason Roberts. Jason describes multiple attribute use case examples and even more advanced methods of creating and using attributes.
About the Author
Matt Ferderer is a software developer who tweets, posts, and blogs about web development.