English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Atributo (Attribute) do C#

特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。

特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。

指定特性(Attribute)

指定特性(Attribute)的语法如下:

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

特性(Attribute)的名称和值是在方括号内指定的,放置在它所应用的元素之前。positional_parameters 指定必需的信息,name_parameter 指定可选的信息。

预定义特性(Attribute)

.Net 框架提供了三种预定义特性:

  • AttributeUsage

  • Condicional

  • Obsoleto

AttributeUsage

预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它指定了特性可应用到的项目的类型。

A sintaxe para especificar esta característica é a seguinte:

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

Dentre eles:

  • 参数 validon 指定特性可放置的语言元素。它是枚举器 AttributeTargets 组合的值。默认值是 AttributeTargets.All

  • parâmetro permitemúltiplos(Opcional) O atributo (property) PermitirMúltiplos fornece um valor booleano. Se for true, a característica é múltipla. O valor padrão é false (única).

  • parâmetro herdado(Opcional) O atributo (property) Herdado O atributo (property) fornece um valor booleano. Se for true, esta característica pode ser herdada pelas subclasses. O valor padrão é false (não herdado).

Por exemplo:

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

Condicional

Esta característica pré-definida marca um método condicional cuja execução depende de um identificador de pré-processamento especificado.

ele causará a compilação condicional de chamadas de métodos, dependendo do valor especificado, como Depuração ou Rastreamento. Por exemplo, ao exibir o valor de uma variável durante a depuração do código.

A sintaxe para especificar esta característica é a seguinte:

[Condicional(
   símboloCondicional
)]

Por exemplo:

[Condicional("DEBUG")]

下面的示例演示了该特性:

#define DEBUG
using System;
using System.Diagnostics;
public class Myclass
{
    [Condicional("DEBUG")]
    public static void Mensagem(string msg)
    {
        Console.WriteLine(msg);
    }
}
class Test
{
    static void função1());
    {
        Myclass.Mensagem("Em Função 1.');
        função2();
    }
    static void função2());
    {
        Myclass.Mensagem("Em Função 2.');
    }
    public static void Main()
    {
        Myclass.Mensagem("Em Função Principal.");
        função1();
        Console.ReadKey();
    }
}

Quando o código acima for compilado e executado, ele produzirá o seguinte resultado:

Em Função Principal
Em Função 1
Em Função 2

Obsoleto

Esta característica pré-definida marca entidades de programa que não devem ser usadas. Ela permite notificar o compilador para descartar um elemento de destino específico. Por exemplo, quando um novo método é usado em uma classe, mas você ainda deseja manter o método antigo na classe, você pode marcar como obsolete (obsoleto) exibindo uma mensagem de que deve ser usada a nova与方法, não o método antigo.

A sintaxe para especificar esta característica é a seguinte:

[Obsoleto(
   mensagem
)]
[Obsoleto(
   mensagem,
   iserror
)]

Dentre eles:

  • parâmetro mensagemÉ uma string que descreve por que o projeto está obsoleto e o que deve ser usado em seu lugar.

  • parâmetro iserrorÉ um valor booleano. Se este valor for true, o compilador deve tratar o uso do projeto como um erro. O valor padrão é false (o compilador gera um aviso).

下面的示例演示了该特性:

using System;
public class MyClass
{
   [Obsolete("Não use OldMethod, use NewMethod em vez disso", true)]
   static void OldMethod()
   { 
      Console.WriteLine("É o método antigo");
   }
   static void NewMethod()
   { 
      Console.WriteLine("É o novo método"); 
   }
   public static void Main()
   {
      OldMethod();
   }
}

当您尝试编译该程序时,编译器会给出一个错误消息说明:

 Não use OldMethod, use NewMethod em vez disso

创建自定义特性(Attribute)

.Net 框架允许创建自定义特性,用于存储声明性的信息,且可在运行时被检索。该信息根据设计标准和应用程序需要,可与任何目标元素相关。

创建并使用自定义特性包含四个步骤:

  • 声明自定义特性

  • 构建自定义特性

  • 在目标程序元素上应用自定义特性

  • 通过反射访问特性

最后一个步骤包含编写一个简单的程序来读取元数据以便查找各种符号。元数据是用于描述其他数据的数据和信息。该程序应使用反射来在运行时访问特性。我们将在下一章详细讨论这点。

声明自定义特性

一个新的自定义特性应派生自 System.Attribute 类。例如:

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

在上面的代码中,我们已经声明了一个名为 DeBugInfo 的自定义特性。

构建自定义特性

让我们构建一个名为 DeBugInfo 的自定义特性,该特性将存储调试程序获得的信息。它存储下面的信息:

  • bug 的代码编号

  • 辨认该 bug 的开发人员名字

  • 最后一次审查该代码的日期

  • 一个存储了开发人员标记的字符串消息

我们的 DeBugInfo 类将带有三个用于存储前三个信息的私有属性(property)和一个用于存储消息的公有属性(property)。所以 bug 编号、开发人员名字和审查日期将是 DeBugInfo 类的必需的定位(posicional)参数,消息将是一个可选的命名(named)参数。

每个特性必须至少有一个构造函数。必需的定位(posicional)参数应通过构造函数传递。下面的代码演示了 DeBugInfo 类:

// 一个自定义特性 BugFix 被赋给类及其成员
[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 = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", \10/10/2012", Message = "Unused variable")]
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 = "Return type mismatch")]
  public double GetArea()
  {
      return length * largura;
  }
  [DeBugInfo(56, "Zara Ali", "19/10/2012)
  public void Display()
  {
      Console.WriteLine("Comprimento: {0}", length);
      Console.WriteLine("Largura: {0}", width);
      Console.WriteLine("Área: {0}", GetArea());
  }
}

No próximo capítulo, usaremos o objeto da classe Reflection para recuperar essas informações.