C#中的特性 Attribute
特性:本质就是一个类,且必须继承至Attribute类
使用场景:(框架,类,方法,属性,字段,参数,返回值....)上面,Attribute通过的一些方法,比如:字段有没有定义特性,用来做判断。
命名规范:【public class 特性名Attribute : Attribute】 定义时Attribute不能实例,使用特性时可以省略只写特性名【特性名Attribute】或【特性名】
特性简单的四个步骤:1.定义---2.使用---3.定义类:通过反射查找到这个特性---4.调用:通过定义的查找特性类去调用。
特性配置:【AttributeUsage(参数1:可以放在方法和类上面默认类等等。参数2:是否可以多重定义特性默认false。参数3:是否可以被继承,默认true。)】
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public class TableAttribute : Attribute //1、定义特性:一个特性就是一个类,特性上面也能加特性 { public string tname { get; set; } public TableAttribute() { } public TableAttribute(string str) { this.tname = str; } } //2、使用特性----------------------------------------------------------------------------- [Serializable]//系统特性,表示可以当前类被实例化 [Table]//自定义特性 [Table("改表名")]//多重属性定义指AttributeUsage参数2:AllowMultiple可以所以多个构造方法 public class Student { [Table]//参数1配置在方法上面也能使用 public void cc() { } } public class ABC : Student { } //当AttributeUsage参数3Inherited改为false,那么也就是说,Student里的特性在ABC里不起作用。
第三步:查找-------第四步:调用,也就是验证字段是否符号要求。相当于约束。
Student stu = new Student(); string str = CustomAttribute.GetTableAttribute(stu);//4.调用 Console.WriteLine(str);//获取到[Table("改表名")]里的字符串参数:改表名 public class CustomAttribute //3.定义一个类专门用来查找特性 { public static string GetTableAttribute<T>(T node) where T:class //约束泛型只能传引用类型 { Type type = typeof(T);//typeof获取到对象名的数据类型 if (type.IsDefined(typeof(TableAttribute), true))//帮你查找看看有没有定义这个特性,第二个参数:是否去找他的派生类,也就是子类中找 { var attribute = type.GetCustomAttributes(typeof(TableAttribute), true);//获取到这个类 return ((TableAttribute)attribute[1]).tname;//上面使用了两个特性,第一个是无参构造,我需要的是第二个值。获取的是obj类型需要强制转换为需要显示的值。 } else { return type.Name; } } }
系统自带的特性
using System.ComponentModel.DataAnnotations;//系统特性需要引用 public class Student { [Key]//主键:如果字段名是id,默认可以不写,如果是usersid这样就认不到必须定义主键。 public int Id { get; set; } [Display(Name ="姓名")]//显示字段别名 [Required]//不能为空 [StringLength(maximumLength:50,MinimumLength =6)]//字符串长度 [EmailAddress]//识别邮箱格式 public string Name { get; set; } }
自定义特性
using System.Reflection;//反射命名空间 using System.Text.RegularExpressions;//正则表达式命名空间 Student stu = new Student() { Id = 1,Name = "dss111@qq.com"}; var res = CustomAttribute.validate(stu); Console.WriteLine(res); CustomAttribute.GetStrNameAttribute(stu);//获取字符串的方法 //3.创建一个类专门查找特性的方法--------------------------------------------------- public class CustomAttribute { public static bool validate<T>(T t) { PropertyInfo[] propertyinfo = t.GetType().GetProperties();//类的成员要通过反射获取,所有属性和特性使用是数组。 foreach (var property in propertyinfo) { if (property.IsDefined(typeof(characteristicAttribute), true)) { var attributes = property.GetCustomAttributes(typeof(characteristicAttribute), true); foreach (var item in attributes) { characteristicAttribute attribute = item as characteristicAttribute;//类型转换,为空不报错,返回null if (!attribute.IsValidate(property.GetValue(t))) return false; } } } return true; } //专门获取字符串的【取别名】 public static void GetStrNameAttribute<T>(T node) where T : class //约束泛型只能传引用类型 { Type type = typeof(T);//获取对象的数据类型。 foreach (var property in type.GetProperties())//GetProperties通过反射获取到类的成员 { if (property.IsDefined(typeof(StringNameAttribute), true)) { var attribute = property.GetCustomAttributes(typeof(StringNameAttribute), true);//获取特性内容 //return ((StringNameAttribute)attribute[0]).tname;//上面使用了两个特性,第一个是无参构造,我需要的是第二个值。获取的是obj类型需要强制转换为需要显示的值。 Console.WriteLine(((StringNameAttribute)attribute[0]).tname+":" + property.Name+":"+ property.GetValue(node)); } } // return type.Name; } } public class Student { [Display("编号")]//显示字段别名 [Key]//主键:如果字段名是id,默认可以不写,如果是usersid这样就认不到必须定义主键。 public int Id { get; set; } [Display("姓名")]//显示字段别名 [Required]//不能为空 [StringLength(50,6)]//字符串长度 [EmailAddress]//识别邮箱格式 public string Name { get; set; } } //1.定义特性----------------------------------------------------------------- abstract class characteristicAttribute : Attribute { public abstract bool IsValidate(object dataValue); } class StringNameAttribute : Attribute //获取字符串的一个公共特性 { public string tname { get; set; } public int i { get; set; }//多字段不写了,原理都差不多 public StringNameAttribute(string str) { this.tname = str; } } //主键 class KeyAttribute : characteristicAttribute { public bool IsPrimaryKey { get; set; } = true; public override bool IsValidate(object dataValue) { return IsPrimaryKey; } } //重新命名,取别名 class DisplayAttribute : StringNameAttribute { public DisplayAttribute(string str) : base(str) { } //把参数传给父类构造方法去执行 public DisplayAttribute(string str,int i) : base(str) { } } //非空验证 class RequiredAttribute : characteristicAttribute { public override bool IsValidate(object dataValue) { return dataValue != null && dataValue.ToString().Length != 0; } } //字符串长度 class StringLengthAttribute : characteristicAttribute { public int maximumLength { get; set; }//最大长度 public int MinimumLength { get; set; }//最小长度 public StringLengthAttribute(int max, int min) { maximumLength = max; MinimumLength = min; } public override bool IsValidate(object dataValue) { return maximumLength >= dataValue.ToString().Length && dataValue.ToString().Length >= MinimumLength; } } //验证邮箱格式 class EmailAddressAttribute : characteristicAttribute { public override bool IsValidate(object dataValue) { //using System.Text.RegularExpressions;//正则表达式命名空间 Regex regex = new Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"); return regex.IsMatch(dataValue.ToString());//字符串是否一样 } }