C# Attribute

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

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

Specifying Attributes (Attribute)

The syntax for specifying an attribute is as follows:

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

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

Predefined Attribute

The .Net framework provides three predefined attributes:

  • AttributeUsage
  • Conditional
  • Obsolete

AttributeUsage

Predefined attributesAttributeUsageDescribes how to use a custom attribute class. It specifies the types of items to which the attribute can be applied.

The syntax for specifying this attribute is as follows:

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

Where:

  • The parameter validon specifies the language elements on which the attribute can be placed. It is an enumerator.AttributeTargetsA combination of values. The default value is AttributeTargets.All。
  • Parameterallowmultiple(Optional) for this attributeAllowMultipleThe property provides a boolean value. If true, the attribute is multi-use. The default value is false (single-use).
  • Parameterinherited(Optional) for this attributeInheritedThe property provides a boolean value. If true, the attribute can be inherited by derived classes. 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 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 asDebugor Trace. For example, when debugging code, display the value of a variable.

The syntax for specifying this attribute 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 attribute marks a program entity that should not be used. It allows you to inform 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 one.

The syntax for specifying this attribute is as follows:

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

Where:

  • Parametermessage, is a string that describes why the item is obsolete and what alternative should be used.
  • Parameteriserror, is a boolean value. If the value is true, the compiler should treat the use of the item 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 attempt to compile the program, the compiler gives an error message stating:

 Don't use OldMethod, use NewMethod instead

Creating custom attributes

The .NET Framework allows creating custom attributes, which are used to store declarative information and can be retrieved at runtime. This information can be related to any target element according to design standards and application requirements.

Creating and using a custom attribute involves four steps:

  • Declaring custom attributes
  • Building custom attributes
  • Apply the custom attribute to the target program element
  • Accessing Attributes via Reflection

The last step involves writing a simple program to read metadata in order to find various symbols. Metadata is data and information used to describe other data. This program should use reflection to access attributes at runtime. We will discuss this in detail in the next chapter.

Declaring custom attributes

A new custom attribute should derive fromSystem.AttributeClass. For example:

// 一个自定义特性 BugFix 被赋给类及其成员
[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 namedDeBugInfoCustom attributes.

Building custom attributes

Let's build one namedDeBugInfocustom attribute, which will store the 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 of the last review of the code
  • A string message storing the developer's notes

ourDeBugInfoThe class will have three private properties for storing the first three pieces of information and a public property for storing the message. Therefore, 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 demonstratesDeBugInfoClass:

Example

// aCustomFeatures BugFix By赋Giveclass anditsmember
[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;
      }
  }
}

Applying custom attributes

applying the 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 will use Reflection class objects to retrieve this information.

other extensions