C#中Attribute特性的用法

開篇語

本文開始之前,首先我想問下大傢對於屬性和特性知道多少?屬性和特性又有何區別?

對於該單詞,我更想把它稱之為:特性。對於屬性和特性就是名稱上有糾葛(不知道你們迷不迷,反正我寫本文之前我是迷瞭),什麼是屬性?屬性是面向對象編程的基本概念,提供瞭對私有字段的訪問封裝,在C#中以get和set訪問器方法實現對可讀可寫屬性的操作,提供瞭安全和靈活的數據訪問封裝。什麼是特性?下面內容就說明下:

介紹

使用特性,可以有效地將元數據或聲明性信息與代碼(程序集、類型、方法、屬性等)相關聯。將特性與程序實體相關聯後,可以在運行時使用 反射 這項技術查詢特性。詳情 用於添加元數據,如編譯器指令和註釋、描述、方法、類等其他信息。.Net 框架提供瞭兩種類型的特性:預定義特性和自定義特性。

簡單總結:定制特性attribute,本質上是一個類,其為目標元素提供關聯附加信息,並在運行期以反射的方式來獲取附加信息。

常用特性

AttributeUsage

AttributeUsage特性用於控制如何應用自定義特性到目標元素,有三個數據屬性可用以修飾我們的自定義的屬性

ValidOn 規定特性可被放置的語言元素。它是枚舉器 AttributeTargets 的值的組合。默認值是 AttributeTargets.All。
AllowMultiple 定義瞭是否可在同一個程序實體上同時使用多個屬性進行修飾
Inherited 定義瞭自定義屬性的修飾是否可由被修飾類的派生類繼承
    [AttributeUsage(validOn: AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
    public class HelpAttribute : Attribute
    {

    }

表示該特定隻能標識在類上,並且同一個類上隻能用一個屬性修飾,並且自定義屬性的修飾不能由修飾類的派生類繼承。

Flags

以Flags特性來將枚舉數值看作位標記,而非單獨的數值,例如我有如下的一個需求,當我想要取得用戶信息的時候,會先從本地緩存中查找,找不到然後從分佈式緩存中查找,最後找不到再從數據庫中查詢。但是有些場景我又不需要查詢數據庫。

所以會建立下面的這種模型

public UserEntity  GetUserInfo(List<DataSource>  dataSources)
{
    var xxxx = new UserEntity();
    if(dataSources.Any(DataSource.Local)
    {
        //從本地緩存中獲取
        return xxxx;
    }
 
    if(dataSources.Any(DataSource.Distribution)
    {
        //從分佈式緩存中獲取
        //更新本地緩存
        return xxxx;
    }
 
    if(dataSources.Any(DataSource.DB)
    {
        //從DB中獲取
        //更新分佈式緩存
        //更新本地緩存
    }
    return xxxx;
}

但是每次調用者都去構建一個List,比較麻煩,此時我們可以使用枚舉中的Flags特性,修改程序如下:

首先是枚舉的定義上,要加上 [Flags] 特性標簽,並且定義 一般都是 2的n次方,主要是便於位移運算

/// <summary>
///數據取得地方
/// </summary>
[Flags]
public enum DataSource
{
    /// <summary>
    ///本地緩存
    /// </summary>
    [Description("本地緩存")]
    LocalCache = 1,
 
    /// <summary>
    ///分佈式緩存
    /// </summary>
    [Description("分佈式緩存")]
    DistributeCache = 2,
 
    /// <summary>
    ///數據庫
    /// </summary>
    [Description("數據庫")]
    DB = 4,
}

修改代碼

public UserEntity  GetUserInfo(DataSource dataSources)
{
    var xxxx = new UserEntity();
    if(dataSources.HasFlags(DataSource.Local)
    {
        //從本地緩存中獲取
        return xxxx;
    }
    if(dataSources.HasFlags(DataSource.Distribution)
    {
        //從分佈式緩存中獲取
        //更新本地緩存
        return xxxx;
    }
    if(dataSources.HasFlags(DataSource.DB)
    {
        //從DB中獲取
        //更新分佈式緩存
        //更新本地緩存
    }
    return xxxx;
}

調用的地方,可以用過“|”來指定,例如我隻想用分佈式緩存和數據庫,那麼:

var userInfo = GetUserInfo(DataSource.Distribution | DataSource.DB);

該例子摘抄自:https://www.jb51.net/article/254408.htm

DllImport

DllImport特性,可以讓我們調用非托管代碼,所以我們可以使用DllImport特性引入對Win32 API函數的調用

[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();

Serializable

Serializable特性表明瞭應用的元素可以被序列化(serializated)

[Serializable]
public class SampleClass
{
    // Objects of this type can be serialized.
}

Conditional

Conditional特性,用於條件編譯,在調試時使用。註意:Conditional不可應用於數據成員和屬性。

自定義特性

可通過定義特性類創建自己的自定義特性,特性類是直接或間接派生自 Attribute 的類,可快速輕松地識別元數據中的特性定義。假設我們希望使用編寫類的程序員名字來標記該類,那麼我們就需要自定義一個Author特性類

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
    public class AuthorAttribute : Attribute
    {
        public string AuthorName;
        public double version;

        public AuthorAttribute(string authorName)
        {
            this.AuthorName = authorName;
            version = 1.0;
        }
    }

類名 AuthorAttribute 是該特性的名稱,即 Author 加上 Attribute 後綴。由於該類繼承自 System.Attribute,因此它是一個自定義特性類。構造函數的參數是自定義特性的位置參數。在此示例中,name 是位置參數。所有公共讀寫字段或屬性都是命名參數。在本例中,version 是唯一的命名參數。

請註意,使用 AttributeUsage 特性可使 Author 特性僅對類和 struct 聲明有效。

可按照下面的方式使用特性

    [Author("張三", version = 1.1)]
    [Author("李四", version = 1.2)]
    public class SampleClass
    {
        // 業務邏輯代碼
    }

獲取自定義參數

var attr = typeof(SampleClass).GetCustomAttributes(typeof(AuthorAttribute), true);

GetCustomAttributes 會以數組形式返回 Author 對象和任何其他特性對象

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: