Class Attribute

Attributes extend classes and types. This C# feature allows you to attach declarative information to any type. Attributes are accessed at compile-time or runtime through the metadata. It is possible to handle types differently based on their attributes.
C# enables programmers to invent new kinds of declarative information, called attributes. Hejlsberg et al., p. 603

This program provides an example of the Obsolete attribute. The Obsolete attribute is a way for you to declare that a method is deprecated and should be avoided. When you look at the program in Visual Studio, this will result in a warning. The actual type referenced by [Obsolete] is ObsoleteAttribute, but you can omit the word Attribute.
Program that uses attribute [C#]
using System;
class Program
{
static void Main()
{
// Warning: 'Program.Test()' is obsolete
Test();
}
[Obsolete]
static void Test()
{
}
}
Warning generated by program
'Program.Test()' is obsolete
Obsolete attribute. The C# language and .NET Framework further provides some useful built-in attribute types for you to use; the Obsolete attribute is one of them. This attribute simply releases annoying warnings or errors when a developer tries to compile a program containing a method that the obsolete attribute is attached to. This can improve maintainability of your software projects.
[Obsolete]An attribute is a regular class that is derived from the Attribute class through normal inheritance. Often, you will want to put an attribute on the class itself, which can provide a way to specify what kind of types the attribute can apply to, among other options. After you declare the attribute class, you can specify to use the attribute with square brackets [ ] and the name of the attribute, omitting the word "Attribute" on the end.
Example attribute program [C#]
using System;
/// <summary>
/// An attribute that can only be attached to classes.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class PerlsAttribute : Attribute
{
}
/// <summary>
/// Use short syntax to reference attribute.
/// </summary>
[Perls]
class Example1
{
}
/// <summary>
/// Use long syntax to reference attribute.
/// </summary>
[PerlsAttribute]
class Example2
{
}
class Program
{
static void Main()
{
// For compilation.
}
}AttributeTargets. lass. The class PerlsAttribute is an attribute class that can only be attached to class types; it cannot be attached to fields, methods, or properties, for example. Also, please notice how you can omit specifying the entire "PerlsAttribute" in the example; you can just use "Perls" optionally.
There are many more options that you can use on your attribute declarations in the C# language. This example builds on the previous one and it includes a string field, a property accessor to that field, and also a parameterful (positional) constructor. When you use this version of PerlsAttribute, you must specify a string type parameter.
Note: Parameterful is a real world. I did not just make it up; someone else made it up.
Example attribute program 2 [C#]
using System;
/// <summary>
/// Attribute.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class PerlsAttribute : Attribute
{
/// <summary>
/// Stores string field.
/// </summary>
string _id;
/// <summary>
/// Attribute constructor.
/// </summary>
public PerlsAttribute(string id)
{
this._id = id;
}
/// <summary>
/// Get Id.
/// </summary>
public string Id
{
get { return this._id; }
}
}
/// <summary>
/// Use.
/// </summary>
[Perls("Dot")]
class Example1
{
}
class Program
{
static void Main()
{
// For compilation.
}
}The specification recommends that named parameters be used, as they are not as likely to be invalidated when the attribute declaration changes. With positional parameters, you rely on the position of the parameters in the attribute constructor; with named parameters, you simply rely on having specified the correct name. For a positional parameter, please remember to include the set accessor in the property. You can combine positional and named parameters.
Example attribute program 3 [C#]
using System;
/// <summary>
/// Attribute.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class PerlsAttribute : Attribute
{
/// <summary>
/// String field.
/// </summary>
string _id;
/// <summary>
/// Attribute constructor.
/// </summary>
public PerlsAttribute()
{
}
/// <summary>
/// Get and set.
/// </summary>
public string Id
{
get { return this._id; }
set { this._id = value; }
}
}
/// <summary>
/// Set property in the attribute.
/// </summary>
[Perls(Id = "Sam")]
class Example1
{
}
class Program
{
static void Main()
{
// For compilation.
}
}
By default an attribute can only be specified a single time on a member or type declaration. To bypass this restriction, you must set the AllowMultiple boolean named parameter to true. To see more on named parameters, please see the section on positional and named attributes above.
Another attribute that is useful in the C# language is the Conditional attribute. Typically, the Conditional attribute is used to disable or enable certain methods depending on whether the compilation mode is DEBUG or RELEASE—these methods must have a void return type.
Conditional Conditional List
The enum type in the C# language has the [Flags] attribute and this can be used to create some useful functions. Please visit the flags article and also the enum category for more on enumerated types.
[Flags]Attributes get more useful when you are faced with the task of using external code such as C++ or C. The DllImport attribute can be attached to extern method declarations; this provides a compile-time signal that allows a program that uses external calls to proceed correctly. Whenever you need to use DllImport, you are bound to have difficulties.
[DllImport]
How can you use attributes in a simple program—one where you do not want to develop your own compiler technology? You can use the reflection feature in the C# language to access attributes at runtime. For example, try getting an array of all the fields in your type, and then performing a different action based on what data the attribute of each type contains. This is sometimes useful for developing debugging mechanisms without modifying important code.
ReflectionAttributes can be accessed during compile-time, and obviously the compiler can take different actions based on what data is contained in the attribute. In compiler theory, the attribute data would become part of the symbol table, which could be used throughout the construction of the object code.

Custom attributes are of fairly limited use in most C# programs, but they provide nearly infinite options for extensibility in your programs, by attaching declarative information to members and types. Through reflection or more advanced systems, you can essentially build new languages into existing C# code. And while attributes have some confusing syntax, they create amazing new possibilities.