C#中Attribute的使用

解讀:首先特性是一個類,它繼承於Attribute。它對程序中的元素進行標註,如類型、字段、方法和屬性等。

Attribute是程序代碼的一部分,它不會被編譯器丟棄,而且還會被編譯器編譯進程序集(Assembly)的元數據(Metadata)裏。

新建一個CustomAttribute的類:

public class CustomAttribute:Attribute
{
    public CustomAttribute()
    {
        Console.WriteLine(nameof(CustomAttribute));
    }
}

在建一個Department類,在類上面加上Custom特性:

[Custom]
public class Department
{
    public Guid id { get; set; }
    public string name { get; set; }

    public void GetName()
    {
        Console.WriteLine(nameof(GetName));
    }
}

我們反編譯Department類查看一下

特性添加後,編譯會在元素內部產生IL,在metadata中會有記錄(這樣就可以通過反射操作它),但是沒辦法直接使用。

無論是在類或類中的元素上面添加特性,反編譯時會看看特性會在類或類中的元素裏面生成一個構造(.ctor())。

特性的多重修飾

 

AllowMultiple=true是指在一個(元素)類中可以多重修飾
AttributeTargets.All表示任何元素類型都可以用其修飾

 

特性其它語法:

 新建一個Student的類,給這個類加上CustomAttribute的特性

[CustomAttribute(123, details = "call")]
public class Students
{
    public int id { get; set; }
    
[CustomAttribute]
public string name { get; set; }
    [Custom]
    [return: Custom]
    public void Method([Custom] string name)
    {
      Console.WriteLine("success");
    }
}

再建一個Manage類,找出Students類上的特性,並進行調用操作等...

public static class Manage
{
    public static void show(Students students)
    {
        //獲取類型
        Type type = typeof(Students);
        //查找是否有CustomAttribute這個特性
        if (type.IsDefined(typeof(CustomAttribute), true))
        {
            //實例化得到一個CustomAttribute類型
            //通過反射創建對象
            CustomAttribute attribute = (CustomAttribute)type.GetCustomAttribute(typeof(CustomAttribute), true);
            Console.WriteLine($"{attribute.details}");
//調用方法 attribute.show(); } } }

調用:

Students students = new Students();
Manage.show(students);

找出Students類中屬性上的的特性

//name爲字段名
PropertyInfo prop = type.GetProperty("name"); if (prop.IsDefined(typeof(CustomAttribute), true)) { //實例化得到一個CustomAttribute類型 //通過反射創建對象 CustomAttribute attribute = (CustomAttribute)prop.GetCustomAttribute(typeof(CustomAttribute), true); Console.WriteLine($"{attribute.details}"); attribute.show(); }

找出Students類中方法上的特性

//Method爲方法名
MethodInfo method = type.GetMethod("Method"); if (method.IsDefined(typeof(CustomAttribute), true)) { //實例化得到一個CustomAttribute類型 //通過反射創建對象 CustomAttribute attribute = (CustomAttribute)method.GetCustomAttribute(typeof(CustomAttribute), true); Console.WriteLine($"{attribute.details}"); attribute.show(); }

找出Students類中方法中參數的特性

ParameterInfo parameter = method.GetParameters()[0];
if (parameter.IsDefined(typeof(CustomAttribute), true))
{
    //實例化得到一個CustomAttribute類型
    //通過反射創建對象
    CustomAttribute attribute = (CustomAttribute)parameter.GetCustomAttribute(typeof(CustomAttribute), true);
    Console.WriteLine($"{attribute.details}");
    attribute.show();
}

找出Students類中方法中返回值的特性

ParameterInfo returnParameter = method.ReturnParameter;
if (returnParameter.IsDefined(typeof(CustomAttribute), true))
{
    //實例化得到一個CustomAttribute類型
    //通過反射創建對象
    CustomAttribute attribute = (CustomAttribute)returnParameter.GetCustomAttribute(typeof(CustomAttribute), true);
    Console.WriteLine($"{attribute.details}");
    attribute.show();
}

通過上面的代碼可以知道,特性可以在沒有破壞封裝的前提下,可以加點額外的信息和行爲,充當補充類使用。

通過特性操作枚舉數據,獲取枚舉字段上的描述信息

public class RemarkExtension
{
    /// <summary>
    /// 用戶狀態
    /// </summary>
    public enum UserState
    {
        [Remark("正常")]
        Normal = 0,//正常  左邊字段名稱,右邊是值
        [Remark("凍結")]
        Frozen = 1,//凍結
        [Remark("刪除")]
        Deleted = 2//刪除
    }

    public class RemarkAttribute : Attribute
    {
        public RemarkAttribute(string remarks)
        {
            this._remarks = remarks;
        }
        public string _remarks;

        public string GetRemark()
        {
            return this._remarks;
        }
    }
}

public static class RemarksExtension
{
//擴展方法是靜態類中的靜態方法,在參數類型前加一個this.可以通過這個類型實例直接調用這個方法。
public static string GetRemarks(this Enum value) { //獲取類型 Type type = value.GetType(); //找到這個字段 FieldInfo fieldInto = type.GetField(value.ToString()); //這個字段上面是否有RemarkAttribute屬性 if (fieldInto.IsDefined(typeof(RemarkAttribute), true)) {
//實例化,將參數賦值給_remarks RemarkAttribute attribute
= (RemarkAttribute)fieldInto.GetCustomAttribute(typeof(RemarkAttribute)); //取值
return attribute.GetRemark(); } else { return value.ToString(); } } }

調用:

UserState userState = UserState.Normal;
Console.WriteLine(userState.GetRemarks());
Console.WriteLine(UserState.Frozen.GetRemarks());
Console.WriteLine(UserState.Deleted.GetRemarks());

 通過特性做數據校驗

public static class ValidataExtension
{
    /// <summary>
    /// 一個object的擴展方法
    /// </summary>
    /// <param name="o"></param>
    /// <returns></returns>
    public static bool Validata(this object o)
    {
        Type type = o.GetType();
        //循環對象裏的所有屬性
        foreach (var prop in type.GetProperties())
        {
            //查看屬性上面是否有LongAttribute這個特性
            //if (prop.IsDefined(typeof(LongAttribute), true))
            //{
            //    LongAttribute attribute = (LongAttribute)prop.GetCustomAttribute(typeof(LongAttribute), true);
            //    if (!attribute.Validata(prop.GetValue(o)))
            //    {
            //        return false;
            //    }
            //}

            //查看屬性上面是否有LengAttribute這個特性
            //if (prop.IsDefined(typeof(LengAttribute), true))
            //{
            //    LengAttribute attribute = (LengAttribute)prop.GetCustomAttribute(typeof(LengAttribute), true);
            //    if (!attribute.Validata(prop.GetValue(o)))
            //    {
            //        return false;
            //    }
            //}

            if (prop.IsDefined(typeof(AbstractValidataAttribute), true))
            {
                //GetCustomAttributes是多個
                //GetCustomAttribute是單個
                object[] attributeArray = prop.GetCustomAttributes(typeof(AbstractValidataAttribute), true);
                foreach (AbstractValidataAttribute attribute in attributeArray)
                {
                    if (!attribute.Validata(prop.GetValue(o)))
                    {
                        return false;
                    }
                }
            }
        }
        return true;
    }
}

/// <summary>
/// 聲明一個抽象類,其它的特性類繼承於它
/// </summary>
public abstract class AbstractValidataAttribute : Attribute
{
    public abstract bool Validata(object value);
}


/// <summary>
/// 判斷string數據的長度
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
// public class LengAttribute : Attribute
public class LengAttribute : AbstractValidataAttribute
{
    private long _min = 0;
    private long _max = 0;
    public LengAttribute(long min, long max)
    {
        this._max = max;
        this._min = min;
    }

    /// <summary>
    /// 重寫父類Validata方法
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public override bool Validata(object value)
    {
        if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
        {
            int length = value.ToString().Length;
            if (length > this._min && length < this._max)
            {
                return true;
            }
        }
        return false;
    }
}

//public class LongAttribute : Attribute
/// <summary>
/// 判斷數據的範圍
/// </summary>
public class LongAttribute : AbstractValidataAttribute
{
    private long _min = 0;
    private long _max = 0;
    public LongAttribute(long min, long max)
    {
        this._max = max;
        this._min = min;
    }

    public override bool Validata(object value)
    {
        if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
        {
            //判斷是否爲long類型,如果是直接給到result
            if (long.TryParse(value.ToString(), out long result))
            {
                if (result > this._min && result < this._max)
                {
                    return true;
                }
            }
        }
        return false;
    }
}
public class Students
{
    public int id { get; set; }

    [LengAttribute(5, 10)]
    public string name { get; set; }

    [LengAttribute(10, 20)]
    public string Acount { get; set; }

    [LongAttribute(10001, 999999999999)]
    public long QQ { get; set; }

    public long _QQ2 = 0;

    public long QQ2
    {
        get
        {
            return this._QQ2;
        }
        set
        {
            if (value > 10001 && value < 99999999999)
            {
                _QQ2 = value;
            }
            else
            {
                throw new Exception("Data error!");
            }
        }
    }
}

調用:

Students students = new Students();
students.study();
students.name = "JavaJava";
students.QQ = 999999;
students.Acount = "c#c#c#c#c#c#c#c#";
students.Validata();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章