什么是特性?你每天上班去公司的时候,都要打开门进去公司工作。突然有一天公司倒闭了,公司的门上贴了一个封条,此时我们已经不能进去大门了,就这一个标签贴着我们就真的进不去大门了吗?那肯定不是,只不过这个封条有法律效应,你要是违反了那你就是在和法律作对。那么这个封条标签就类似于特性,它可以让你进入公司之前走一些流程,或者不让你进去公司。
- Attribute用来在代码中附加一些元信息,这些元信息可被编译器、.NET Framework、或者我们的程序使用。方法、属性、类等上都可以标注Attribute。
- 命名一般以Attribute结尾,如果以Attribute结尾的话使用的时候可以省略Attribute。
- 在Type、MethodInfo、PropertyInfo等上都可以调用object[] GetCustomAttributes(Type attributeType, bool inherit)获取标注的注解对象,因为同一个Attribute可能标注多次,所以返回值是数组。
例如Obsolete:表示该特性已过时。
[Obsolete("该类已经过时", true)] public class OldClass { [method: Obsolete("该方法已经过时")] public void OldMethod() { Console.WriteLine("我是一个方法"); } }
当我们实例化该类的时候,编译器直接告诉我们该类已过时,运行的时候直接报错。
我们选择Obsolete按F12进去,我们可以看到ObsoleteAttribute继承Attribute,里面有Message和Error属性,再接着就是几个构造函数了。有人就会有疑问了,就这两个东西就能让编译器警告?当然不是了,之所以它能让编译器警告,是因为编译器对它进行了语义分析。那么我可以继承它自己也写一个特性让编译出错吗?你再仔细看下ObsoleteAttribute是不是有一个关键字sealed,这个关键字直接让你无法继承它。那么我们可以继承Attribute,在写下其他特性,就不要纠结这个了。
自定义特性
//该特性适用于所有的类,而且是非继承的。 [AttributeUsage(AttributeTargets.Class, Inherited = false)] class OldAttribute : Attribute { private string discretion; public string Discretion { get { return discretion; } set { discretion = value; } } public DateTime date; public OldAttribute(string discretion) { this.discretion = discretion; date = DateTime.Now; } }
[Old("我是一个特性")] public class SampleClass { public SampleClass() { Console.WriteLine("1111"); } }
public class NewClass : SampleClass { public void NewTest() { Console.WriteLine("222"); } }
好了写到这里就写完了,是不是就大功告成了呢?当然不是了,想要使用它,我们还必须用反射去获取这个特性里面的属性值。mvc框架里面之所以拿来直接用,那是因为它框架里为你处理了这些过程。
public static void GetAttributeInfo(Type t) { //检索自定义属性 OldAttribute old = (OldAttribute)Attribute.GetCustomAttribute(t, typeof(OldAttribute)); if (old == null) { Console.WriteLine(t.ToString() + "类中自定义特性不存在"); } else { Console.WriteLine("特性描述:{0} 加入事件时间:{1}", old.Discretion, old.date); } }
调用:
static void Main(string[] args) { GetAttributeInfo(typeof(SampleClass)); Console.WriteLine("================="); GetAttributeInfo(typeof(NewClass)); }
结果:
我们在写一个:
public class TableNameAttribute : Attribute { public TableNameAttribute() { } public string TableName { get; set; } }
然后我们放到创建的User类上:
[TableName(TableName = "Users")] public class User { public int Id { get; set; } public string Name { get; set; } }
调用:
/// <summary> /// 为类或成员添加描述信息,然后在使用的时候拿到该信息。 /// </summary> public static void TableShow() { Type type = typeof(User); object[] obj = type.GetCustomAttributes(true); for (int i = 0; i < obj.Length; i++) { if (obj[i] is TableNameAttribute) { TableNameAttribute tnAttr = (TableNameAttribute)obj[i]; Console.WriteLine(tnAttr.TableName); } } }
结果:
我们再试试下在枚举中使用特性:
/// <summary> /// 备注特性 /// </summary> public class RemarkAttribute : Attribute { private string Remark { get; set; } public RemarkAttribute(string _remark) { this.Remark = _remark; } public string GetRemark() { return this.Remark; } }
public enum Sex { [Remark("男的")] boy = 1, [Remark("女的")] girl = 2 }
调用:
/// <summary> /// 备注属性 /// </summary> public static class EnumExtension { public static string GetRemake(Enum model) { if (model is Sex) { Type t = typeof(Sex); FieldInfo fi = t.GetField(model.ToString()); object[] o = fi.GetCustomAttributes(true); foreach (var attr in o) { if (attr is RemarkAttribute) { RemarkAttribute remark = (RemarkAttribute)attr; return remark.GetRemark(); } } } return string.Empty; } }
EnumExtension.GetRemake(Sex.boy)
我们在看看验证一个类型范围:
/// <summary> /// 验证范围 /// </summary> public class IntValidateAttribute : Attribute { /// <summary> /// 最小值 /// </summary> private int minValue { get; set; } /// <summary> /// 最大值 /// </summary> private int maxValue { get; set; } /// <summary> /// 构造函数 /// </summary> /// <param name="minValue"></param> /// <param name="maxValue"></param> public IntValidateAttribute(int minValue, int maxValue) { this.minValue = minValue; this.maxValue = maxValue; } /// <summary> /// 检验值是否合法 /// </summary> /// <param name="checkValue"></param> /// <returns></returns> public bool Validate(int checkValue) { return checkValue >= minValue && checkValue <= maxValue; } }
public class User { [IntValidate(1, 10)] public int Id { get; set; } public string Name { get; set; } }
public class BaseDal { public static string Insert<T>(T model) { Type type = typeof(T); //反射该类型的所有属性 PropertyInfo[] infos = type.GetProperties(); bool boIsCheck = true; foreach (var item in infos) { //找寻所有的特性的 object[] o = item.GetCustomAttributes(true); if (item.PropertyType.Name.ToLower().Contains("int")) { foreach (var attr in o) { IntValidateAttribute intValidate = (IntValidateAttribute)attr; //执行特性的验证逻辑 boIsCheck = intValidate.Validate((int)item.GetValue(model)); } } if (!boIsCheck) { break; } } if (boIsCheck) { return "验证通过,插入数据库成功"; } else { throw new Exception("验证失败"); } } }
调用:
只要我们这个ID的范围在1-10以内就符合,否则就报错。
string msg = BaseDal.Insert<User>(new User() { Id = 2, Name = "zero219" });
结果: