熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

C#特性詳解

2022-06-13   來源: .NET編程 

   C#特性詳解

  特性提供功能強大的方法用以將元數據或聲明信息與代碼(程序集類型方法屬性等)相關聯特性與程序實體關聯後即可在運行時使用名為反射的技術查詢特性這篇文章絕大部分是按照MSDN來學習的只是加了一點點自己的東東官方介紹的很詳細我們就一起來了解一下它的用法

  特性具有以下屬性

  特性可向程序中添加元數據元數據是有關在程序中定義的類型的信息所有的 NET 程序集都包含指定的一組元數據這些元數據描述在程序集中定義的類型和類型成員可以添加自定義特性以指定所需的任何附加信息

  可以將一個或多個特性應用到整個程序集模塊或較小的程序元素(如類和屬性)

  特性可以與方法和屬性相同的方式接受參數

  程序可以使用反射檢查自己的元數據或其他程序內的元數據

  這些都是官方的定義那麼對於一個初學者來說看的懂漢字不難但是上面的元數據是什麼?

  我這麼通俗的解釋下

  你注意過程序及編譯的時候的pdb文件了嗎?pdb文件裡面存儲了關於程序集內部的所有的成員信息例如成員的數據類型屬性類型方法返回值方法入參類型就是程序及內部所有的定義信息的數據信息是存儲定義信息的一類數據信息程序集裡面的所有的關於聲明類的數據信息包括方法間調用都是存儲在元數據裡面

  下面開始一同學習特性的用法

  特性可以放置在幾乎所有的聲明中在 C# 中特性的指定方法為將括在方括號中的特性名置於其應用到的實體的聲明上方

  [SystemSerializable]

  public class SampleClass

  {

  // Objects of this type can be serialized

  }

  一個聲明上可放置多個特性

  using SystemRuntimeInteropServices;

  …

  void MethodA([In][Out] ref double x) { }

  void MethodB([Out][In] ref double x) { }

  void MethodC([In Out] ref double x) { }

  某些特性對於給定實體可以指定多次例如ConditionalAttribute 就是一個可多次使用的特性

  [Conditional(DEBUG Conditional(TEST)]

  void TraceMethod()

  {

  // …

  }

  根據約定所有特性名稱都以單詞Attribute結束以便將它們與NET Framework中的其他項區分但是在代碼中使用特性時不需要指定 attribute 後綴例如[DllImport] 雖等效於 [DllImportAttribute]但 DllImportAttribute 才是該特性在 NET Framework 中的實際名稱

  特性參數

  許多特性都有參數而這些參數可以是定位參數未命名參數或命名參數任何定位參數都必須按特定順序指定並且不能省略而命名參數是可選的且可以按任意順序指定首先指定定位參數例如這三個特性是等效的

  [DllImport(userdll)]

  [DllImport(userdll SetLastError=false ExactSpelling=false)]

  [DllImport(userdll ExactSpelling=false SetLastError=false)]

  第一個參數(DLL 名稱)是定位參數並且總是第一個出現其他參數為命名參數在這種情況下兩個命名參數均默認為 false因此可將其省略有關默認參數值的信息可以參考參考各個特性的文檔

  特性目標

  特性的目標是應用該特性的實體例如特性可以應用於類特定方法或整個程序集默認情況下特性應用於它後面的元素但是您也可以顯式標識要將特性應用於方法還是它的參數或返回值

  若要顯式標識特性目標請使用下面的語法

  [target : attributelist]

  下表顯示了可能的 target 值的列表


  C# dataguid=aacecbcfbeeadceee>C#

  適用對象

  assembly

  整個程序集

  module

  當前程序集模塊(不同於 Visual Basic 模塊)

  field

  在類或結構中的字段

  event

  Event

  method

  get and set property accessors dataguid=cdefbdffcfdfddc>方法或 get 和 set 屬性訪問器

  param

  set property accessor parameters dataguid=eebcbbdbc>方法參數或 set 屬性訪問器參數

  property

  Property

  return

  get property accessor dataguid=cdeaaffbecbaba>方法屬性索引器或 get 屬性訪問器的返回值

  type

  結構接口枚舉或委托

  下面的示例演示如何將特性應用於程序集和模塊

  using System;

  using SystemReflection;

  [assembly: AssemblyTitleAttribute(Production assembly )]

  [module: CLSCompliant(true)]

  下面的示例演示如何在 C# 中將特性應用於方法方法參數和方法返回值

  // default: applies to method

  [SomeAttr]

  int Method() { return ; }

  // applies to method

  [method: SomeAttr]

  int Method() { return ; }

  // applies to return value

  [return: SomeAttr]

  int Method() { return ; }

  無論規定 SomeAttr 應用於什麼目標都必須指定 return 目標即使 SomeAttr 被定義為僅應用於返回值也是如此換言之編譯器將不使用 AttributeUsage 信息解析不明確的特性目標

  呀終於了解完了是時候自己十一下手了我們就動手活動一下頸骨多加點注釋來關聯一下學過的內容

  我們這裡拿ObsoleteAttribute做下測試它標記不再使用的程序元素此類不能被繼承首先我們看一下它的繼承結構

  <fp src=http://imgeducitycn/img_///png>

  當然我們看看其他的特性我們就會發現特性其實是從SystemObject類派生出來的一種特殊類

  我們現在用這個構造來驗證

  public ObsoleteAttribute(string message bool error)

  參數                         類型

  message                   System ::String        描述可選的變通方法的文本字符串

  error                    System ::Boolean       指示是否將使用已過時的元素視為錯誤的布爾值

  

  總之我們在使用特性的時候不要產生畏懼就當他是特殊的類以前怎麼樣用構造函數現在仍舊怎麼用只是格式有點微妙的變化

  using System;

  namespace 特性

  {

  class Program

  {

  static void Main(string[] args)

  {

  OldClass old = new OldClass()//個報錯因為使用OldClass兩次             oldOldMethod()//警告因為第二個參數未指定使用已過時的元素不會視為錯誤

  ConsoleReadKey()

  }

  }

  [Obsolete(該類已經過時true)]//使用默認的特性目標直接作用於緊隨其後的Class OldClass

  //第二個參數我這裡設置為true將使用已過時的元素視為錯誤

  class OldClass

  {

  [method: Obsolete(該方法已經過時)]

  public void OldMethod()

  {

  ConsoleWriteLine(過時的方法!

  }

  }

  }

  運行以後會出現兩個錯誤提示一個警告提示

  <fp src=http://imgeducitycn/img_///png>


    好了現在我們在緊接著學習自定義特性這個估計就算是相當簡單了
    自定義特性
    通過定義一個特性類可以創建您自己的自定義特性該特性類直接或間接地從Attribute派生有助於方便快捷地在元數據中標識特性定義假設您要用編寫類型的程序員的名字標記類型可以定義一個自定義 Author特性類
    [SystemAttributeUsage(SystemAttributeTargetsClass |
    SystemAttributeTargetsStruct)
    ]
    public class Author : SystemAttribute
    {
    private string name;
    public double version;
    public Author(string name)
    {
    thisname = name;
    version = ;
    }
    }
    類名是特性的名稱即 Author它由 SystemAttribute 派生而來因此是自定義特性類構造函數的參數是自定義特性的定位參數本示例中 name 是定位參數任何公共的讀寫字段或屬性都是命名參數在本例中version 是唯一的命名參數請注意 AttributeUsage 特性的用法它使得 Author 特性僅在類聲明中有效
    可以按如下所示使用此新特性
    [Author(P Ackerman version = )]
    class SampleClass
    {
    // P Ackermans code goes here…
    }
    AttributeUsage 有一個命名參數 AllowMultiple使用它可以使自定義特性成為一次性使用或可以使用多次的特性在下面的代碼示例中創建了一個使用多次的特性
    [SystemAttributeUsage(SystemAttributeTargetsClass |
    SystemAttributeTargetsStruct
    AllowMultiple = true)  // multiuse attribute
    ]
    public class Author : SystemAttribute
    在下面的代碼示例中向某個類應用了同一類型的多個特性
    [Author(P Ackerman version = )]
    [Author(R Koch version = )]
    class SampleClass
    {
    // P Ackermans code goes here…
    // R Kochs code goes here…
    }
    如果特性類包含一個屬性則該屬性必須為讀寫屬性
   
    介紹完了官方的示例是不是還是雲裡霧裡那麼我們一起來深入解剖一下
    首先我們從上面可以總結出創建自定義特性的大概步驟
    應用AttributeUsage特性 雖然等效但AttributeUsageAttribute 才是該特性在 NET Framework 中的實際名稱它也是由 SystemAttribute 派生而來
    聲明特性類它由 SystemAttribute 派生而來
    聲明構造函數
    聲明特性
    OVER!!!就這麼回事完了嗎我們繼續剖析之重要的信息AttributeUsage特性
    AttributeUsage特性研究特性當然首要的要研究其構造函數現在我們來看看他是怎麼定義的
    public AttributeUsageAttribute( AttributeTargets validOn)
    參數   validOn 類型SystemAttributeTargets 使用按位運算符組合的一組值用於指示哪些程序元素是有效的
    用指定的 AttributeTargetsAllowMultiple 值和 Inherited 值列表初始化 AttributeUsageAttribute 類的新實例
    於是乎我們返回到了研究AttributeTargets的問題了現在我們就來細心的看看他是神馬!
    原來他是一個枚舉通過該特性可使其成員值按位組合可以通過按位運算組合 AttributeTargets 枚舉值來獲得首選組合
    成員


  成員名稱 說明 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Assembly 可以對程序集應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Module 可以對模塊應用特性


注意http://imgeducitycn/img_///gif>注意
Module refers to a portable executable file (dll orexe) and not a Visual Basic standard module dataguid=ccbbfdeaefc>Module 指的是可移植的可執行文件(dll 或 exe)而非 Visual Basic 標准模塊 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Class 可以對類應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Struct 可以對結構應用特性即值類型 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Enum 可以對枚舉應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Constructor 可以對構造函數應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Method 可以對方法應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Property 可以對屬性應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Field 可以對字段應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Event 可以對事件應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Interface 可以對接口應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Parameter 可以對參數應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> Delegate 可以對委托應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> ReturnValue 可以對返回值應用特性 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> GenericParameter 可以對泛型參數應用特性


注意http://imgeducitycn/img_///gif>注意
目前此特性可以應用僅於 C#Microsoft 中間語言 (MSIL) 和發出的代碼 由 XNA Framework 提供支持 alt=由 XNA Framework 提供支持 src=http://imgeducitycn/img_///gif>fsPortableClassLibrary(zhcnVS)gif alt=fafsPortableClassLibrary(zhcnVS)gif src=http://imgeducitycn/img_///gif> All 可以對任何應用程序元素應用特性





  到了這裡一節也就明了了謎底都一一展現在我們的面前

  按照上面的經驗再次開始動手來熟悉這一切我指定了該自定義的特性不可繼承就在不解釋別的了只是為了證明一下命名參數Inherited定性成功與否總之還是很簡單的





? cellPadding= border=>

































































csharp keyword>using csharp plain>System;
csharp spaces 
csharp keyword>namespace csharp plain>特性
csharp plain>{
csharp spaces>    csharp keyword>class csharp plain>Program
csharp spaces>    csharp plain>{
csharp spaces>        csharp keyword>static csharp keyword>void csharp plain>Main(csharp keyword>stringcsharp plain>[] args)
csharp spaces>        csharp plain>{
csharp spaces>            csharp plain>GetAttributeInfo(csharp keyword>typeofcsharp plain>(OldClass));
csharp spaces>            csharp plain>ConsoleWriteLine(csharp string>==============csharp plain>);
csharp spaces>            csharp plain>GetAttributeInfo(csharp keyword>typeofcsharp plain>(NewClass));
csharp spaces>            csharp plain>ConsoleReadKey();
csharp spaces>        csharp plain>}
csharp spaces>        csharp keyword>public csharp keyword>static csharp keyword>void csharp plain>GetAttributeInfo(Type t)
csharp spaces>        csharp plain>{
csharp spaces>            csharp plain>OldAttribute myattribute = (OldAttribute)AttributeGetCustomAttribute(t csharp keyword>typeofcsharp plain>(OldAttribute));
csharp spaces>            csharp keyword>if csharp plain>(myattribute == csharp keyword>nullcsharp plain>)
csharp spaces>            csharp plain>{
csharp spaces>                csharp plain>ConsoleWriteLine(tToString()+csharp string>類中自定義特性不存在!csharp plain>);
csharp spaces>            csharp plain>}
csharp spaces>            csharp keyword>else
csharp spaces>            csharp plain>{
csharp spaces>                csharp plain>ConsoleWriteLine(csharp string>特性描述:{}\n加入事件{}csharp plain> myattributeDiscretion myattributedate);
csharp spaces>            csharp plain>}
csharp spaces>        csharp plain>}
csharp spaces>    csharp plain>}
csharp spaces 
csharp spaces>   csharp plain>[AttributeUsage(AttributeTargetsClassInherited=csharp keyword>falsecsharp plain>)]csharp comments>//設置了定位參數和命名參數
csharp spaces 
csharp spaces>        csharp comments>//該特性適用於所有的類而且是非繼承的
csharp spaces>    csharp keyword>class csharp plain>OldAttribute : Attributecsharp comments>//繼承自Attribute
csharp spaces>    csharp plain>{
csharp spaces>        csharp keyword>private csharp keyword>string csharp plain>discretion;
csharp spaces 
csharp spaces>        csharp keyword>public csharp keyword>string csharp plain>Discretion
csharp spaces>        csharp plain>{
csharp spaces>            csharp keyword>get csharp plain>{ csharp keyword>return csharp plain>discretion; }
csharp spaces>            csharp keyword>set csharp plain>{ discretion = value; }
csharp spaces>        csharp plain>}
csharp spaces>        csharp keyword>public csharp plain>DateTime date;
csharp spaces>        csharp keyword>public csharp plain>OldAttribute(csharp keyword>string csharp plain>discretion)
csharp spaces>        csharp plain>{
csharp spaces>            csharp keyword>thiscsharp plain>discretion = discretion;
csharp spaces>            csharp plain>date = DateTimeNow;
csharp spaces>        csharp plain>}
csharp spaces>    csharp plain>}
csharp spaces>    csharp comments>//現在我們定義兩類
csharp spaces>    csharp plain>[Old(csharp string>這個類將過期csharp plain>)]csharp comments>//使用定義的新特性
csharp spaces>    csharp keyword>class csharp plain>OldClass
csharp spaces>    csharp plain>{
csharp spaces>        csharp keyword>public csharp keyword>void csharp plain>OldTest()
csharp spaces>        csharp plain>{
csharp spaces>            csharp plain>ConsoleWriteLine(csharp string>測試特性csharp plain>);
csharp spaces>        csharp plain>}
csharp spaces>    csharp plain>}
csharp spaces>    csharp keyword>class csharp plain>NewClass:OldClass
csharp spaces>    csharp plain>{
csharp spaces>        csharp keyword>public csharp keyword>void csharp plain>NewTest()
csharp spaces>        csharp plain>{
csharp spaces>            csharp plain>ConsoleWriteLine(csharp string>測試特性的繼承csharp plain>);
csharp spaces>        csharp plain>}
csharp spaces>    csharp plain>}
csharp spaces>    csharp comments>//我們寫一個方法用來獲取特性信息
csharp plain>}

  運行效果

  <fp src=http://imgeducitycn/img_///png>



From:http://tw.wingwit.com/Article/program/net/201311/12800.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.