In C#, Attributes are metadata tags assigned to code, including classes, types, methods, and fields. Using reflection, you can examine the tags to change behaviors in your program. We’ll show how to use them, and how to write your own.
What Are Attributes?
Simply put, attributes are metadata tags that hold some information. The syntax for them is the type name in square brackets above the code being tagged, like so:
They can be attached to pretty much anything—classes, methods, fields, structs, types, etc. They can even be given parameters to provide input that can be accessed, though they are limited to basic types. You can set parameters by invoking the attribute like a method:
A common use case is marking fields for serialization. C# has a built-in [Serializable] tag, which supports serializing a class to bytes, and many third-party libraries will implement their own tags. For example, the C# driver for MongoDB includes many tags for serializing to Bson, and also a special tag that will interpret a string as the document ID.
Another common use case is tagging methods that are managed by a higher-level command handler. For example, a Discord Bot, registers a list of commands that get handled whenever someone sends a message. Rather than manually adding each command to the command handler every time you write a new one, you can instead tag the method with [Command(“commandname”)], and use the generic solution that will add them all automatically at runtime.
You can read Microsoft’s documentation to learn more, but they’re quite simple.
How To Make Your Own Attributes
Of course, you can pretty easily create your own custom attributes to apply to your classes. All you have to do is create a class that extends from System.Attribute. You can also add an attribute on this class specifying how it should be used; for example, only applying to classes or structs.
Then, you can specify fields, and a constructor that will take the input params and populate the fields. When you use this attribute, it’s like calling new Attribute(params), except without the new keyword.
Then you’re free to use them to tag your code, provided that the attribute is referenced in the code being tagged.
To access attributes programmatically, you’ll need to use reflection. Reflection isn’t great for performance, but for the use cases of attributes, that usually doesn’t matter. You can use Attribute.GetCustomAttributes to return an Attribute[], passing in the type of the class:
If you want to access all instance of attributes across your assembly, you can use Assembly.GetExecutingAssembly().GetTypes() to fetch a list of executing types and then check all the custom attributes of that type to see if it contains the search parameter, optionally filtering that list based on the type of class the attribute is attached to.
To access attribute parameters, you simply access them directly from the Attribute class, like any other public properties.