How to create your own custom attributes in C#
Custom attributes in C# can be used to add metadata or additional information to our code elements, such as classes, methods, and properties. It allows us to add runtime and user-defined properties to our code annotations that can be inspected and used. Custom attributes are a form of declarative programming, providing a means to describe additional information about code elements without directly affecting the code’s behavior.
Imagine you’re a shipping company manager and have to assign certain packages with specific handling instructions. To do this, create a set of unique labels or tags that indicate the different package handling requirements. Let’s look at the steps on how we can apply the above example:
Custom attributes: We create custom labels or tags such as “Fragile,” “Perishable,” and “Do Not Stack.”
Application: These custom attributes are attached to specific packages based on their contents.
Instructions: Handlers can quickly identify packages marked with these custom attributes and apply appropriate care or handling procedures. For instance, a package labeled “Fragile” might need to be handled delicately, while “Perishable” packages might require expedited shipping.
Concepts and considerations
Let’s have a look at the key points about custom attributes:
Declaration: Custom attributes are defined by creating custom attribute classes. These classes inherit from the
System.Attributeclass and can have properties, fields, or other members to store additional information.Application: We can apply custom attributes to code elements like classes, methods, properties, fields, and parameters. It is typically done by including the attribute’s name in square brackets before the code element.
Metadata: Custom attributes add metadata to code, which tools, libraries, or other code at runtime can use. For example, attributes can be used for documentation generation, serialization, and validation.
Reflection: We can use reflection to access the information stored in custom attributes at runtime. Reflection allows us to inspect and query attributes applied to code elements.
Attribute usage: The attribute usage property can be used when defining a custom attribute to determine where it can be applied and whether it can be applied to the same code element at multiple instances.
Steps to create custom attributes
Define the custom attribute class: Creates a reusable attribute to attach additional information to classes, methods, and properties. Line 1 Inherits from the
Attributeclass, making it a custom attribute. Line 3 has a propertySomePropertyto store custom data.
public class OurCustomAttribute : Attribute{public string SomeProperty { get; set; }}
Apply our custom attribute: Our custom attribute can be applied to many code elements, including properties, methods, and classes. On line 1 the attribute is applied using square brackets
[]before the element’s declaration. On lines 4 and 14 theSomePropertyis set with different values for each element.
[OurCustomAttribute(SomeProperty = "ClassAttribute")]public class OurClass{[OurCustomAttribute(SomeProperty = "MethodAttribute")]public void YourMethod(){Console.WriteLine("Executing YourMethod");int result = AddNumbers(7, 3);Console.WriteLine($"Result of adding numbers: {result}");}[OurCustomAttribute(SomeProperty = "OurPropertyAttribute")]public string OurProperty { get; set; }}
Access custom attribute values: We can use reflection to access the values of our custom attribute at runtime. On lines 3, 15, and 27 the
GetCustomAttributemethod is used to retrieve the attribute instances, and the values ofSomePropertyare then printed. If the attribute is not found for a particular code element, a corresponding message is printed:
Type type = typeof(OurClass);OurCustomAttribute classAttribute = (OurCustomAttribute)type.GetCustomAttribute(typeof(OurCustomAttribute));if (classAttribute != null){string propertyValue = classAttribute.SomeProperty;Console.WriteLine($"Class Attribute: {propertyValue}");}else{Console.WriteLine("Class Attribute not found.");}MethodInfo methodInfo = type.GetMethod("YourMethod");OurCustomAttribute methodAttribute = (OurCustomAttribute)methodInfo.GetCustomAttribute(typeof(OurCustomAttribute));if (methodAttribute != null){string methodValue = methodAttribute.SomeProperty;Console.WriteLine($"Method Attribute: {methodValue}");}else{Console.WriteLine("Method Attribute not found.");}PropertyInfo propertyInfo = type.GetProperty("OurProperty");OurCustomAttribute propertyAttribute = (OurCustomAttribute)propertyInfo.GetCustomAttribute(typeof(OurCustomAttribute));if (propertyAttribute != null){string propertyValue = propertyAttribute.SomeProperty;Console.WriteLine($"Property Attribute: {propertyValue}");}else{Console.WriteLine("Property Attribute not found.");}
Code example
Let’s take a look at the code example on how we can use custom attributes to annotate our code elements with additional metadata and then use reflection to access and utilize that metadata at runtime.
using System;using System.Reflection;public class OurCustomAttribute : Attribute{public string SomeProperty { get; set; }}[OurCustomAttribute(SomeProperty = "ClassAttribute")]public class OurClass{[OurCustomAttribute(SomeProperty = "MethodAttribute")]public void YourMethod(){Console.WriteLine("Executing YourMethod");// Some code inside YourMethodint result = AddNumbers(7, 3);Console.WriteLine($"Result of adding numbers: {result}");}[OurCustomAttribute(SomeProperty = "OurPropertyAttribute")]public string OurProperty { get; set; }private int AddNumbers(int a, int b){return a + b;}}class Program{static void Main(){Type type = typeof(OurClass);OurCustomAttribute classAttribute = (OurCustomAttribute)type.GetCustomAttribute(typeof(OurCustomAttribute));if (classAttribute != null){string propertyValue = classAttribute.SomeProperty;Console.WriteLine($"Class Attribute: {propertyValue}");}else{Console.WriteLine("Class Attribute not found.");}MethodInfo methodInfo = type.GetMethod("YourMethod");OurCustomAttribute methodAttribute = (OurCustomAttribute)methodInfo.GetCustomAttribute(typeof(OurCustomAttribute));if (methodAttribute != null){string methodValue = methodAttribute.SomeProperty;Console.WriteLine($"Method Attribute: {methodValue}");}else{Console.WriteLine("Method Attribute not found.");}PropertyInfo propertyInfo = type.GetProperty("OurProperty");OurCustomAttribute propertyAttribute = (OurCustomAttribute)propertyInfo.GetCustomAttribute(typeof(OurCustomAttribute));if (propertyAttribute != null){string propertyValue = propertyAttribute.SomeProperty;Console.WriteLine($"Property Attribute: {propertyValue}");}else{Console.WriteLine("Property Attribute not found.");}}}
Explanation
Lines 4–7: A custom attribute class
OurCustomAttributeis defined, which inherits fromAttribute. This custom attribute has a propertySomePropertythat can be set with a string value.Lines 9–29: The
OurCustomAttributeis applied to different code elements:It’s applied to the
OurClassclass, withSomePropertyset to “ClassAttribute.”It’s applied to the
YourMethodmethod, withSomePropertyset to “MethodAttribute.”It’s applied to the
OurPropertyproperty, withSomePropertyset to “OurPropertyAttribute.”
Lines 31–72: In the
Mainmethod, the code uses reflection to retrieve and print the custom attribute values applied to the class, method, and property:It obtains the type of the
OurClassclass.It attempts to get the
OurCustomAttributeapplied to the class, method, and property usingGetCustomAttribute.If an attribute is found for a specific code element, it retrieves and prints the
SomePropertyvalue. If an attribute is not found, it displays an appropriate message.
Free Resources