C# Attributes

C# Attributes

**Attribute (Attribute)** is a declarative label used to transfer behavioral information of various elements (such as classes, methods, structures, enumerations, components, etc.) in the program at runtime. You can add declarative information to your program by using attributes. A declarative tag is described by placing square brackets ([ ]) in front of the element it applies to.

Attributes are used to add metadata such as compiler directives and comments, descriptions, methods, classes, and other information. The .Net framework provides two types of attributes: predefined attributes and custom attributes.

prescribed characteristic (Attribute)

The syntax for specifying attributes is as follows:

[attribute(positional_parameters, name_parameter = value, ...)]
element

The name and value of an attribute is specified within square brackets, before the element to which it applies. positional_parameters specifies required information, and name_parameter specifies optional information.

predefined attribute (Attribute)

The .Net framework provides three predefined features:

  • AttributeUsage
  • Conditional
  • Obsolete

AttributeUsage

The predefined attribute AttributeUsage describes how to use a custom attribute class. It specifies the type of item to which the attribute can be applied.

The syntax for specifying this property is as follows:

[AttributeUsage(
   validon,
   AllowMultiple=allowMultiple,
   Inherited=inherited
)]

in:

  • The parameter validon specifies the language elements on which the attribute can be placed. It is a combination of the values of the enumerator AttributeTargets. The default is AttributeTargets.All.
  • The parameter allowmultiple (optional) provides a boolean value for the attribute’s AllowMultiple property. If true, the feature is multipurpose. The default is false (single-use).
  • The parameter inherited (optional) provides a boolean value for the attribute’s Inherited property. If true, the attribute is inheritable by derived classes. The default is false (not inherited).

For example:

[AttributeUsage(AttributeTargets. Class |
AttributeTargets. Constructor|
AttributeTargets. Field|
AttributeTargets.Method|
AttributeTargets. Property,
AllowMultiple = true)]

Conditional

This predefined attribute 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, displaying the value of a variable while debugging code.

The syntax for specifying this property is as follows:

[Conditional(
   conditionalSymbol
)]

For example:

[Conditional("DEBUG")]

The following example demonstrates this feature:

Instance

#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 result:

In Main function.
In Function 1.
In Function 2.

Obsolete

This predefined property marks program entities that should not be used. It allows you to tell the compiler to discard a specific 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 by displaying a message that the new method should be used instead of the old method. of).

The syntax for specifying this property is as follows:

[Obsolete(
   message
)]
[Obsolete(
   message,
   iserror
)]

in:

  • The parameter message, is a string describing why the item is obsolete and what should be used instead.
  • The parameter iserror, is a Boolean value. If the value is true, the compiler should treat use of this item as an error. The default 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 an error message stating:

 Don't use OldMethod, use NewMethod instead

Create a custom attribute (Attribute)

The .Net framework allows the creation of custom attributes that store declarative information that can be retrieved at runtime. This information can be associated with any target element depending on the design criteria and application needs.

Creating and using custom properties consists of four steps:

  • Declare custom attributes
  • Build custom properties
  • Apply custom attributes on target program elements
  • Access properties via reflection

The last 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 properties at runtime. We will discuss this in detail in the next chapter.

declare custom attributes

A new custom attribute should be derived from the System.Attribute class. For example:

// A custom attribute BugFix is assigned to the class and its members
[AttributeUsage(AttributeTargets. Class |
AttributeTargets. Constructor|
AttributeTargets. Field|
AttributeTargets.Method|
AttributeTargets. Property,
AllowMultiple = true)]

public class DeBugInfo : System.Attribute

In the code above, we have declared a custom attribute called DeBugInfo .

Build Custom Attributes

Let’s build a custom attribute called DeBugInfo that will store information obtained by the debugger. It stores the following information:

  • The code number of the bug
  • The name of the developer who identified the bug
  • The date the code was last reviewed
  • A string message storing developer flags

Our DeBugInfo class will have three private properties to store the first three information and one public property to store the message. So the bug number, developer name and review date will be required positional parameters of the DeBugInfo class, and the message will be an optional named parameter.

Every attribute must have at least one constructor. Required positional parameters should be passed through the constructor. The following code demonstrates the DeBugInfo class:

Example

// A custom attribute BugFix is assigned to the 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 an attribute 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’ll use Reflection class objects to retrieve this information.