How to use custom attributes in C#
By FoxLearn 1/18/2025 3:00:29 AM 146
The Description
attribute stores a user-friendly description of a class or property, which can be read and displayed during runtime.
Unit testing frameworks identify test methods by looking for the TestMethod
attribute.
Web APIs often use attributes like HttpGet
and validation attributes such as Required
for model validation.
Create the Custom Attribute
To create a custom attribute, you need to inherit from the Attribute
class.
Here's an example of a custom attribute that stores the priority level of a task:
public class PriorityLevelAttribute : Attribute { public int Priority { get; } public PriorityLevelAttribute(int priority) { Priority = priority; } }
Attribute constructor parameters must be constant values, so you cannot pass variables or objects at runtime, only constants like numbers or enums.
Apply the Attribute
Next, you can apply this PriorityLevelAttribute
to an enum or class. Here, we apply it to an enum representing different task statuses:
public enum TaskStatus { [PriorityLevel(1)] HighPriority, [PriorityLevel(2)] MediumPriority, [PriorityLevel(3)] LowPriority }
In this example, we’ve set different priority levels for each status of a task.
Retrieve the Attribute Value at Runtime
To access the attribute value at runtime, you'll use reflection. Below is an example of how to extract the priority value from a TaskStatus
enum:
using System; using System.Reflection; using System.Linq; public static class TaskStatusExtensions { public static int GetPriority(this TaskStatus status) { Type taskStatusType = typeof(TaskStatus); string statusName = Enum.GetName(taskStatusType, status); MemberInfo[] memberInfo = taskStatusType.GetMember(statusName); if (memberInfo.Length != 1) { throw new ArgumentException($"TaskStatus of {status} should only have one memberInfo"); } IEnumerable<PriorityLevelAttribute> customAttributes = memberInfo[0].GetCustomAttributes<PriorityLevelAttribute>(); PriorityLevelAttribute priorityAttribute = customAttributes.FirstOrDefault(); if (priorityAttribute == null) { throw new InvalidOperationException($"TaskStatus of {status} has no PriorityLevelAttribute"); } return priorityAttribute.Priority; } }
Alternatively, you can use a more concise version by creating a generic method to retrieve any attribute:
public static class TaskStatusExtensions { private static T GetAttribute<T>(this TaskStatus status) where T : Attribute { return (status.GetType().GetMember(Enum.GetName(status.GetType(), status))[0] .GetCustomAttributes(typeof(T), inherit: false)[0] as T); } public static int GetPriority(this TaskStatus status) { return status.GetAttribute<PriorityLevelAttribute>().Priority; } }
Use the Attribute in Practice
Now you can use the custom attribute to determine the priority of a task and act accordingly.
Console.WriteLine("Task processing..."); Task[] tasks = LoadTasks(); // implementation not shown foreach (var task in tasks) { int priority = task.Status.GetPriority(); Console.WriteLine($"Task {task.Name} has priority level {priority}"); // Simulate processing based on priority if (priority == 1) { Console.WriteLine("Processing high-priority task first."); } else if (priority == 2) { Console.WriteLine("Processing medium-priority task next."); } else { Console.WriteLine("Processing low-priority task last."); } } Console.ReadKey();
In this example, we use the GetPriority
extension method to fetch the priority level of each task and determine its processing order based on the priority level defined with the PriorityLevelAttribute
.
- Using the OrderBy and OrderByDescending in LINQ
- Querying with LINQ
- Optimizing Performance with Compiled Queries in LINQ
- MinBy() and MaxBy() Extension Methods in .NET
- SortBy, FilterBy, and CombineBy in NET 9
- Exploring Hybrid Caching in .NET 9.0
- Using Entity Framework with IDbContext in .NET 9.0
- Primitive types in C#