C# Attribute

АтрибутЭто декларативный тег, используемый для передачи информации о поведении различных элементов программы (таких как классы, методы, структуры, перечисления, компоненты и т. д.) во время выполнения. Вы можете добавлять декларативную информацию в программу с помощью атрибутов. Декларативный тег описывается путем размещения квадратных скобок ([ ]) перед элементом, к которому он применяется.

Атрибуты используются для добавления метаданных, таких как инструкции компилятора и комментарии, описания, методы, классы и другая информация. Платформа .Net предоставляет два типа атрибутов:предопределённыеатрибуты ипользовательскиеатрибуты.

Указание атрибутов (Attribute)

Синтаксис указания атрибута выглядит следующим образом:

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

Имя и значение атрибута указываются в квадратных скобках и размещаются перед элементом, к которому он применяется. positional_parameters задают обязательную информацию, а name_parameter задает необязательную информацию.

Предопределённый атрибут

Платформа .Net предоставляет три предопределённых атрибута:

  • AttributeUsage
  • Conditional
  • Obsolete

AttributeUsage

Предопределённые атрибутыAttributeUsageОписывает, как использовать класс пользовательского атрибута. Он указывает типы элементов, к которым можно применить атрибут.

Синтаксис указания этого атрибута выглядит следующим образом:

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

Где:

  • Параметр validon задаёт элементы языка, в которых может быть размещён атрибут. Это перечисление.AttributeTargetsКомбинация значений. Значение по умолчанию — AttributeTargets.All。
  • Параметрallowmultiple(Необязательный) для этого атрибутаAllowMultipleСвойство предоставляет логическое значение. Если true, атрибут может использоваться многократно. Значение по умолчанию — false (однократное использование).
  • Параметрinherited(Необязательный) для этого атрибутаInheritedСвойство предоставляет логическое значение. Если true, атрибут может наследоваться производными классами. Значение по умолчанию — false (не наследуется).

Например:

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

Conditional

Этот предопределённый атрибут помечает условный метод, выполнение которого зависит от указанного идентификатора предварительной обработки.

Он вызывает условную компиляцию вызовов методов в зависимости от указанного значения, такого какDebugили Trace. Например, при отладке кода отображать значение переменной.

Синтаксис указания этого атрибута выглядит следующим образом:

[Conditional(
   conditionalSymbol
)]

Например:

[Conditional("DEBUG")]

В следующем примере демонстрируется эта возможность:

Пример

#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("В функции 1.");
        function2();
    }
    static void function2()
    {
        Myclass.Message("В функции 2.");
    }
    public static void Main()
    {
        Myclass.Message("В функции Main.");
        function1();
        Console.ReadKey();
    }
}

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

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

Obsolete

Этот предопределённый атрибут помечает сущность программы, которую не следует использовать. Он позволяет сообщить компилятору, чтобы тот игнорировал конкретный целевой элемент. Например, когда в классе используется новый метод, но вы всё ещё хотите сохранить старый метод в классе, вы можете пометить его как устаревший, отобразив сообщение о том, что вместо старого метода следует использовать новый.

Синтаксис указания этого атрибута выглядит следующим образом:

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

Где:

  • Параметрmessage— строка, которая описывает, почему элемент устарел и какую альтернативу следует использовать.
  • Параметрiserror— логическое значение. Если значение равно true, компилятор должен рассматривать использование этого элемента как ошибку. Значение по умолчанию — false (компилятор создаёт предупреждение).

В следующем примере демонстрируется эта возможность:

Пример

using System;
public class MyClass
{
   [Obsolete("Не используйте OldMethod, используйте вместо этого NewMethod", true)]
   static void OldMethod()
   {
      Console.WriteLine("Это старый метод");
   }
   static void NewMethod()
   {
      Console.WriteLine("Это новый метод");
   }
   public static void Main()
   {
      OldMethod();
   }
}

Когда вы пытаетесь скомпилировать программу, компилятор выдаёт сообщение об ошибке:

 Don't use OldMethod, use NewMethod instead

Создание пользовательских атрибутов

.NET Framework позволяет создавать настраиваемые атрибуты, которые используются для хранения декларативной информации и могут быть извлечены во время выполнения. Эта информация может быть связана с любым целевым элементом в соответствии со стандартами проектирования и требованиями приложения.

Создание и использование настраиваемого атрибута включает четыре этапа:

  • Объявление настраиваемых атрибутов
  • Построение настраиваемых атрибутов
  • Применение настраиваемого атрибута к целевому элементу программы
  • Доступ к атрибутам через отражение

Последний этап включает написание простой программы для чтения метаданных с целью поиска различных символов. Метаданные — это данные и информация, используемые для описания других данных. Эта программа должна использовать отражение для доступа к атрибутам во время выполнения. Мы подробно обсудим это в следующей главе.

Объявление настраиваемых атрибутов

Новый настраиваемый атрибут должен наследоваться от классаSystem.Attribute. Например:

// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]

public class DeBugInfo : System.Attribute

В приведенном выше коде мы объявили настраиваемый атрибут с именемDeBugInfoНастраиваемые атрибуты.

Построение настраиваемых атрибутов

Давайте создадим один настраиваемый атрибут с именемDeBugInfo, который будет хранить информацию, полученную отладчиком. Он хранит следующую информацию:

  • Кодовый номер ошибки
  • Имя разработчика, обнаружившего ошибку
  • Дата последней проверки кода
  • Строковое сообщение, хранящее заметки разработчика

нашDeBugInfoУ класса будет три закрытых свойства для хранения первых трёх фрагментов информации и открытое свойство для хранения сообщения. Следовательно, номер ошибки, имя разработчика и дата проверки будут обязательными позиционными параметрами класса DeBugInfo, а сообщение — необязательным именованным параметром.

Каждый атрибут должен иметь как минимум один конструктор. Обязательные позиционные параметры должны передаваться через конструктор. Следующий код демонстрируетDeBugInfoкласс:

Пример

// 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;
      }
  }
}

Применение пользовательских атрибутов

применение атрибута путём размещения его непосредственно перед целевым объектом:

Пример

[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Несоответствие типа возвращаемого значения")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Неиспользуемая переменная")]
class Rectangle
{
  // Переменные-члены
  protected double length;
  protected double width;
  public Rectangle(double l, double w)
  {
      length = l;
      width = w;
  }
  [DeBugInfo(55, "Zara Ali", "19/10/2012",
  Message = "Несоответствие типа возвращаемого значения")]
  public double GetArea()
  {
      return length * width;
  }
  [DeBugInfo(56, "Zara Ali", "19/10/2012")]
  public void Display()
  {
      Console.WriteLine("Длина: {0}", length);
      Console.WriteLine("Ширина: {0}", width);
      Console.WriteLine("Площадь: {0}", GetArea());
  }
}

В следующей главе мы будем использовать объекты класса Reflection для извлечения этой информации.

Другие расширения