C#Attribute的使用
阿新 • • 發佈:2020-06-27
解讀:首先特性是一個類,它繼承於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();