In C#, attributes are a powerful way to add metadata to your code.
You’ve probably seen attributes like [Obsolete], [Serializable], or [Required] before.
But did you know you can also create your own custom attributes?
In this article, we’ll walk through the basics of creating and using custom attributes in C# — step by step.
What is an Attribute?
An attribute in C# is a class that inherits from System.Attribute.
You can use attributes to decorate classes, methods, properties, parameters, and more — to store additional information about those elements.
Attributes are metadata compiled into your program. Attributes themselves do not add any functionality to a class, property or module – just data. However, using reflection, one can leverage those attributes in order to create functionality.
For example:
[Obsolete("This method is deprecated. Use NewMethod instead.")]
public void OldMethod() { }
public class Person
{
[Sanitize]
public string Name {get; set;}
}
Here, the Obsolete attribute tells the compiler to warn you when OldMethod is used.
The Sanitize attribute, for example, indicates that a field of a DTO should be cleaned of special characters.
Why Create Custom Attributes?
Built-in attributes are useful, but sometimes you need to attach your own metadata.
For example:
- Mark certain classes as “special” in your application.
- Add version or author information.
- Configure behavior at runtime.
How to Create a Custom Attribute
Let’s create a simple custom attribute that marks a property as required — something similar to data annotations.
Step 1: Define the Attribute Class
We want our attribute to work on properties, so we specify AttributeTargets.Property.
[AttributeUsage(AttributeTargets.Property)]
public class RequiredPropertyAttribute : Attribute
{
public string ErrorMessage { get; set; }
public RequiredPropertyAttribute(string errorMessage = "This property is required.")
{
ErrorMessage = errorMessage;
}
}
Explanation:
- The class inherits from
System.Attribute. - We use
[AttributeUsage(AttributeTargets.Property)]to ensure it can only be applied to properties. - The constructor has an optional
ErrorMessageparameter.
Step 2: Use the Custom Attribute
Now we can decorate properties in our class with the RequiredPropertyAttribute:
public class Person
{
[RequiredProperty("Name cannot be empty.")]
public string Name { get; set; }
public int Age { get; set; }
[RequiredProperty]
public string Email { get; set; }
}
Here:
NameandEmailare marked as required.Ageis optional.
Step 3: Validate Properties Using Reflection
At runtime, you can write a small utility that checks if all required properties have values:
using System;
using System.Reflection;
public class Program
{
public static void Main()
{
var person = new Person
{
Name = null,
Age = 30,
Email = null
};
ValidateRequiredProperties(person);
}
public static void ValidateRequiredProperties(object obj)
{
var type = obj.GetType();
foreach (var prop in type.GetProperties())
{
var attr = prop.GetCustomAttribute<RequiredPropertyAttribute>();
if (attr != null)
{
var value = prop.GetValue(obj);
if (value == null || (value is string s && string.IsNullOrWhiteSpace(s)))
{
Console.WriteLine($"Property '{prop.Name}' is required. {attr.ErrorMessage}");
}
}
}
}
}
Output:
Property 'Name' is required. Name cannot be empty.
Property 'Email' is required. This property is required.
Summary
✅ We defined a custom attribute that applies only to properties.
✅ We used it to mark certain properties as required.
✅ We wrote a simple validator to check for missing required properties at runtime.
This pattern is very useful for scenarios like:
- Input validation.
- Mapping metadata for ORM frameworks.
- Generating UI dynamically based on attributes.
- Aspect Oriented Programming