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();