C# 特性(Attribute)

2022-06-14 14:04 更新

C# 特性(Attribute)

特性(Attribute)是用于在運(yùn)行時(shí)傳遞程序中各種元素(比如類、方法、結(jié)構(gòu)、枚舉、組件等)的行為信息的聲明性標(biāo)簽。您可以通過使用特性向程序添加聲明性信息。一個(gè)聲明性標(biāo)簽是通過放置在它所應(yīng)用的元素前面的方括號([ ])來描述的。

特性(Attribute)用于添加元數(shù)據(jù),如編譯器指令和注釋、描述、方法、類等其他信息。.Net 框架提供了兩種類型的特性:預(yù)定義特性和自定義特性。

規(guī)定特性(Attribute)

規(guī)定特性(Attribute)的語法如下:

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

特性(Attribute)的名稱和值是在方括號內(nèi)規(guī)定的,放置在它所應(yīng)用的元素之前。positional_parameters 規(guī)定必需的信息,name_parameter 規(guī)定可選的信息。

預(yù)定義特性(Attribute)

.Net 框架提供了三種預(yù)定義特性:

  • AttributeUsage
  • Conditional
  • Obsolete

AttributeUsage

預(yù)定義特性 AttributeUsage 描述了如何使用一個(gè)自定義特性類。它規(guī)定了特性可應(yīng)用到的項(xiàng)目的類型。

規(guī)定該特性的語法如下:

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

其中:

  • 參數(shù) validon 規(guī)定特性可被放置的語言元素。它是枚舉器 AttributeTargets 的值的組合。默認(rèn)值是 AttributeTargets.All
  • 參數(shù) allowmultiple(可選的)為該特性的 AllowMultiple 屬性(property)提供一個(gè)布爾值。如果為 true,則該特性是多用的。默認(rèn)值是 false(單用的)。
  • 參數(shù) inherited(可選的)為該特性的 Inherited 屬性(property)提供一個(gè)布爾值。如果為 true,則該特性可被派生類繼承。默認(rèn)值是 false(不被繼承)。

例如:

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

Conditional

這個(gè)預(yù)定義特性標(biāo)記了一個(gè)條件方法,其執(zhí)行依賴于它頂?shù)念A(yù)處理標(biāo)識符。

它會引起方法調(diào)用的條件編譯,取決于指定的值,比如 Debug Trace。例如,當(dāng)調(diào)試代碼時(shí)顯示變量的值。

規(guī)定該特性的語法如下:

[Conditional(
   conditionalSymbol
)]

例如:

[Conditional("DEBUG")]

下面的實(shí)例演示了該特性:

#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();
    }
}

當(dāng)上面的代碼被編譯和執(zhí)行時(shí),它會產(chǎn)生下列結(jié)果:

In Main function
In Function 1
In Function 2

C# 中利用 Conditional 定義條件方法

利用 Conditional 屬性,程序員可以定義條件方法。Conditional 屬性通過測試條件編譯符號來確定適用的條件。當(dāng)運(yùn)行到一個(gè)條件方法調(diào)用時(shí),是否執(zhí)行該調(diào)用,要根據(jù)出現(xiàn)該調(diào)用時(shí)是否已定義了此符號來確定。如果定義了此符號,則執(zhí)行該調(diào)用;否則省略該調(diào)用(包括對調(diào)用的參數(shù)的計(jì)算)。

使用 Conditional 是封閉 #if 和 #endif 內(nèi)部方法的替代方法,它更整潔,更別致、減少了出錯(cuò)的機(jī)會。

條件方法要受到以下限制:

  • 條件方法必須是類聲明或結(jié)構(gòu)聲明中的方法。如果在接口聲明中的方法上指定 Conditional 屬性,將出現(xiàn)編譯時(shí)錯(cuò)誤。
  • 條件方法必須具有返回類型。
  • 不能用 override 修飾符標(biāo)記條件方法。但是,可以用 virtual 修飾符標(biāo)記條件方法。此類方法的重寫方法隱含為有條件的方法,而且不能用 Conditional 屬性顯式標(biāo)記。
  • 條件方法不能是接口方法的實(shí)現(xiàn)。否則將發(fā)生編譯時(shí)錯(cuò)誤。
  • 如果條件方法用在“委托創(chuàng)建表達(dá)式”中,也會發(fā)生編譯時(shí)錯(cuò)誤

這里需要注意的是:如果創(chuàng)建一個(gè)沒有定義任何條件的方法,那么默認(rèn)只要調(diào)用就總是會執(zhí)行此方法,如果你想通過條件來判斷執(zhí)行,那么該方法上必須至少包含一個(gè)conditional特性所定義的條件,它才會響應(yīng)你定義的條件

Obsolete

這個(gè)預(yù)定義特性標(biāo)記了不應(yīng)被使用的程序?qū)嶓w。它可以讓您通知編譯器丟棄某個(gè)特定的目標(biāo)元素。例如,當(dāng)一個(gè)新方法被用在一個(gè)類中,但是您仍然想要保持類中的舊方法,您可以通過顯示一個(gè)應(yīng)該使用新方法,而不是舊方法的消息,來把它標(biāo)記為 obsolete(過時(shí)的)。

規(guī)定該特性的語法如下:

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

其中:

  • 參數(shù) message,是一個(gè)字符串,描述項(xiàng)目為什么過時(shí)的原因以及該替代使用什么。
  • 參數(shù) iserror,是一個(gè)布爾值。如果該值為 true,編譯器應(yīng)把該項(xiàng)目的使用當(dāng)作一個(gè)錯(cuò)誤。默認(rèn)值是 false(編譯器生成一個(gè)警告)。

下面的實(shí)例演示了該特性:

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();
   }
}

當(dāng)您嘗試編譯該程序時(shí),編譯器會給出一個(gè)錯(cuò)誤消息說明:

Don't use OldMethod, use NewMethod instead

創(chuàng)建自定義特性(Attribute)

.Net 框架允許創(chuàng)建自定義特性,用于存儲聲明性的信息,且可在運(yùn)行時(shí)被檢索。該信息根據(jù)設(shè)計(jì)標(biāo)準(zhǔn)和應(yīng)用程序需要,可與任何目標(biāo)元素相關(guān)。

創(chuàng)建并使用自定義特性包含四個(gè)步驟:

  • 聲明自定義特性
  • 構(gòu)建自定義特性
  • 在目標(biāo)程序元素上應(yīng)用自定義特性
  • 通過反射訪問特性

最后一個(gè)步驟包含編寫一個(gè)簡單的程序來讀取元數(shù)據(jù)以便查找各種符號。元數(shù)據(jù)是用于描述其他數(shù)據(jù)的數(shù)據(jù)和信息。該程序應(yīng)使用反射來在運(yùn)行時(shí)訪問特性。我們將在下一章詳細(xì)討論這點(diǎn)。

聲明自定義特性

一個(gè)新的自定義特性應(yīng)派生自 System.Attribute 類。例如:

// 一個(gè)自定義特性 BugFix 被賦給類及其成員
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]

public class DeBugInfo : System.Attribute

在上面的代碼中,我們已經(jīng)聲明了一個(gè)名為 DeBugInfo 的自定義特性。

構(gòu)建自定義特性

讓我們構(gòu)建一個(gè)名為 DeBugInfo 的自定義特性,該特性將存儲調(diào)試程序獲得的信息。它存儲下面的信息:

  • bug 的代碼編號
  • 辨認(rèn)該 bug 的開發(fā)人員名字
  • 最后一次審查該代碼的日期
  • 一個(gè)存儲了開發(fā)人員標(biāo)記的字符串消息

我們的 DeBugInfo 類將帶有三個(gè)用于存儲前三個(gè)信息的私有屬性(property)和一個(gè)用于存儲消息的公有屬性(property)。所以 bug 編號、開發(fā)人員名字和審查日期將是 DeBugInfo 類的必需的定位( positional)參數(shù),消息將是一個(gè)可選的命名(named)參數(shù)。

每個(gè)特性必須至少有一個(gè)構(gòu)造函數(shù)。必需的定位( positional)參數(shù)應(yīng)通過構(gòu)造函數(shù)傳遞。下面的代碼演示了 DeBugInfo 類:

// 一個(gè)自定義特性 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;
      }
  }
}

應(yīng)用自定義特性

通過把特性放置在緊接著它的目標(biāo)之前,來應(yīng)用該特性:

[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 * 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());
  }
}

在下一章中,我們將使用 Reflection 類對象來檢索這些信息。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號