解讀:首先特性是一個類,它繼承於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();