C# attribute
An Attribute is a declarative tag used to pass behavior information about various elements in a program, such as classes, methods, structures, enumerations, components, and so on, at run time. You can add declarative information to your program by using features. A declarative tag is made by placing square brackets in front of the element to which it applies ( []
) to describe it.
Attribute is used to add metadata, such as compiler instructions and comments, descriptions, methods, classes, and other information. The .Net
framework provides two types of properties: predefined properties and custom properties.
Specified Attribute
The syntax for Attribute is as follows:
[attribute(positional_parameters, name_parameter = value, ...)]
element
The name and value of the Attribute are specified in square brackets and areplaced before the element to which it applies. positional_parameters
specify the necessary information, name_parameter
specify optional information.
Predefined Attribute
The .Net
framework provides three predefined features:
AttributeUsage
Conditional
Obsolete
AttributeUsage
Predefined property AttributeUsage
describes how to use a custom property class. It specifies the type of project to which the feature can beapplied.
The syntax that specifies this feature is as follows:
[AttributeUsage(
validon,
AllowMultiple=allowmultiple,
Inherited=inherited
)]
Where:
The parameter
validon
specifies the language element in which the featurecan be placed. It is a combination of the values of the enumeratorAttributeTargets
.The default isAttributeTargets.All
.The parameter
allowmultiple
(optional) for this featureAllowMultiple
property provides a Boolean value. If true, this feature is multipurpose. The default value is false (for single use).The parameter
inherited
(optional) for this featureInherited
property provides a Boolean value. If true, the property can be inherited by a derived class. The default value is false (not inherited).
For example:
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
Conditional
This predefined property marks a conditional method whose execution depends on the specified preprocessing identifier.
It causes conditional compilation of method calls, depending on the specified value, such as Debug
or Trace
. For example, the value of a variable is displayed when debugging code.
The syntax that specifies this feature is as follows:
[Conditional(
conditionalSymbol
)]
For example:
[Conditional("DEBUG")]
The following example demonstrates this feature:
Example
#define DEBUG
using System;
using System.Diagnostics;
public class Myclass
{
[Conditional("DEBUG")]
public static void Message(string msg)
{
Console.WriteLine(msg);
}
}
class Test
{
static void function1()
{
Myclass.Message("In Function 1.");
function2();
}
static void function2()
{
Myclass.Message("In Function 2.");
}
public static void Main()
{
Myclass.Message("In Main function.");
function1();
Console.ReadKey();
}
}
When the above code is compiled and executed, it produces the following results:
In Main function.
In Function 1.
In Function 2.
Obsolete
This predefined feature marks program entities that should not be used. It allows you to tell the compiler to discard a particular target element. For example, when a new method is used in a class, but you still want to keep the old method in the class, you can mark it as obsolete (outdated) by displaying a message that should use the new method instead of the old one.
The syntax that specifies this feature is as follows:
[Obsolete(
message
)]
[Obsolete(
message,
iserror
)]
Where:
The parameter
message
is a string that describes why the project is out of date and what the alternative uses.The parameter
iserror
is a Boolean value. If the value is true, the compiler should treat the use of the project as an error. The default value is false (the compiler generates a warning).
The following example demonstrates this feature:
Example
using System;
public class MyClass
{
[Obsolete("Don't use OldMethod, use NewMethod instead", true)]
static void OldMethod()
{
Console.WriteLine("It is the old method");
}
static void NewMethod()
{
Console.WriteLine("It is the new method");
}
public static void Main()
{
OldMethod();
}
}
When you try to compile the program, the compiler gives you an errormessage:
Don't use OldMethod, use NewMethod instead
Create a custom attribute
The framework .Net
allows you to create custom features that store declarative information and can be retrieved at run time. This information can be related to any target element based on design standards and application needs.
Creating and using custom properties involves four steps:
Declare custom properties
Build custom features
Apply custom properties to target program elements
Access properties through reflection
The final step involves writing a simple program to read the metadata in order to find various symbols. Metadata is data and information used to describe other data. The program should use reflection to access features atrun time. We will discuss this in detail in the next chapter.
Declare custom properties
A new custom feature should be derived from the System.Attribute
class.For example:
// A custom attribute BugFix is assigned to a class and its members
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute
In the above code, we have declared a file named DeBugInfo
custom properties.
Build custom features
Let’s build a file named DeBugInfo
, which stores the information obtainedby the debugger. It stores the following information:
Code number of bug
Identify the name of the developer of the bug
The date the code was last reviewed
A string message that stores developer tags
The DeBugInfo
class will have three private propertiesfor storing the first three information and a public propertyfor storing messages. So the bug number, developer name, and review date will be required positional parameters for the DeBugInfo class, and the message will be an optional named parameter.
Each property must have at least one constructor. The required positional parameters should be passed through the constructor. The following code demonstrates DeBugInfo
class:
Example
// A custom attribute BugFix is assigned to a class and its members
[AttributeUsage(AttributeTargets.Class \|
AttributeTargets.Constructor \|
AttributeTargets.Field \|
AttributeTargets.Method \|
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute
{
private int bugNo;
private string developer;
private string lastReview;
public string message;
public DeBugInfo(int bg, string dev, string d)
{
this.bugNo = bg;
this.developer = dev;
this.lastReview = d;
}
public int BugNo
{
get
{
return bugNo;
}
}
public string Developer
{
get
{
return developer;
}
}
public string LastReview
{
get
{
return lastReview;
}
}
public string Message
{
get
{
return message;
}
set
{
message = value;
}
}
}
Apply custom properties
Apply a property by placing it immediately before its target:
Example
[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type
mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
class Rectangle
{
// Member variables
protected double length;
protected double width;
public Rectangle(double l, double w)
{
length = l;
width = w;
}
[DeBugInfo(55, "Zara Ali", "19/10/2012",
Message = "Return type mismatch")]
public double GetArea()
{
return length * width;
}
[DeBugInfo(56, "Zara Ali", "19/10/2012")]
public void Display()
{
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}
In the next chapter, we will use the Reflection
class object to retrieve this information.