C#--特性的运用试验
以下是学习笔记:
一,特性运用试验(一)
需求1:传统的代码
有这样一个用户状态的枚举类型:
namespace _015_特性.EnumExtend { /// <summary> /// 枚举:用户的状态 /// </summary> public enum UserState { /// <summary> /// 正常 /// </summary> Normal=0, /// <summary> /// 冻结 /// </summary> Frozen=1, /// <summary> /// 删除 /// </summary> Deleted=2 } }
如果想要知道用户的状态,代码这样写:
UserState userState = UserState.Frozen; if (userState == UserState.Normal) { Console.WriteLine("正常"); } else if (userState == UserState.Frozen) { Console.WriteLine("冻结"); } else if (userState == UserState.Deleted) { Console.WriteLine("删除"); }
上面的代码存在这样的问题:
如果状态要改变(正常,删除,冻结,,),改代码就非常的费劲,每次都要判断很多次
需求1:运用特性后的代码思路
【1】,先定义一个特性
namespace _015_特性.EnumExtend { //自定义Attribute,特性上还可以加特性 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] //参数1:可以被哪些情况下使用,如果是All就是被所有情况下都可以用。 //参数2:是否可以标记多个特性 //参数3:是否可以被继承 public class RemarkAttribute:Attribute { /// <summary> /// 状态特性 /// </summary> /// <param name="remark"></param> public RemarkAttribute(string remark) { this.Remark = remark; } public string Remark { get;private set; } } }
【2】,特性定义好了之后,标记特性
namespace _015_特性.EnumExtend { /// <summary> /// 枚举:用户的状态 /// </summary> public enum UserState { /// <summary> /// 正常 /// </summary> [Remark("正常")] Normal=0, /// <summary> /// 冻结 /// </summary> [Remark("冻结")] Frozen = 1, /// <summary> /// 删除 /// </summary> [Remark("删除")] Deleted = 2 } }
【3】写一个调用特性方法的类
namespace _015_特性.EnumExtend { /// <summary> /// 特性调用的类,用来调用特性的 /// </summary> public class AttributeInvoke { public string GetRemark(UserState userState) { Type type = userState.GetType();//获取到传过来的类型 var fileId = type.GetField(userState.ToString());//根据参数这个值找到具体的字段 if(fileId.IsDefined(typeof(RemarkAttribute),true)) //查找字段有没有有定义RemarkAttribute这个特性, { RemarkAttribute remarkAttribute = (RemarkAttribute) fileId.GetCustomAttribute(typeof(RemarkAttribute), true); return remarkAttribute.Remark;//如果找到了,就返回这个特性的属性 } else { return userState.ToString();//如果找不到,就返回传过来的这个值 } } } }
【4】在主程序中调用
UserState userState2 = UserState.Frozen; AttributeInvoke attributeInvoke=new AttributeInvoke(); Console.WriteLine(attributeInvoke.GetRemark(userState2));
改用特性的好处总结:不用if else的判断了,直接把userState2当做参数传入方法attributeInvoke.GetRemark(userState2)就可以啦。
总结上面的过程:定义特性--标记特性--调用(需要用到发射的技术)
二,特性运用试验(二),特性验证
【1】定义带特性的抽象类
namespace _015_特性.ValidateExtend { /// <summary> /// 带有抽象方法的抽象类 /// </summary> public abstract class AbstractValidateAttribute:Attribute { /// <summary> /// 验证数据的方法 /// </summary> /// <param name="objValue"></param> /// <returns></returns> public abstract bool Validate(object objValue); } }
【2】写三个实现抽象类的实现验证类
1,
namespace _015_特性.ValidateExtend { [AttributeUsage(AttributeTargets.Property)] public class LongAttribute : AbstractValidateAttribute { private long _Long = 0; public LongAttribute(long phoneLength) { this._Long = phoneLength; } /// <summary> /// 检验手机号是否为11位 /// </summary> /// <param name="objValue"></param> /// <returns></returns> public override bool Validate(object objValue) { return objValue != null && objValue.ToString().Length == 11; } } }
2,
namespace _015_特性.ValidateExtend { public class RequriedAttribute : AbstractValidateAttribute { /// <summary> /// 检验值是否为空 /// </summary> /// <param name="objValue"></param> /// <returns></returns> public override bool Validate(object objValue) { return objValue != null && !string.IsNullOrWhiteSpace(objValue.ToString()); } } }
3,
namespace _015_特性.ValidateExtend { [AttributeUsage(AttributeTargets.Property)] public class StringLengthAttribute : AbstractValidateAttribute { private int _Min = 0; private int _Max = 0; public StringLengthAttribute(int min,int max) { this._Min = min; this._Max = max; } /// <summary> /// 验证字符串的长度 /// </summary> /// <param name="objValue"></param> /// <returns></returns> public override bool Validate(object objValue) { return objValue != null && objValue.ToString().Length >= this._Min && objValue.ToString().Length <= this._Max; } } }
【3】,写一个调用方法的类
namespace _015_特性.ValidateExtend { public static class AttributeExtend { /// <summary> /// 调用特性的方法的类(扩展方法) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <returns></returns> public static bool Validate<T>(this T t) { Type type = t.GetType();//找到t参数的类型 foreach (var property in type.GetProperties())//从类型里面查找遍历所有的属性 { if (property.IsDefined(typeof(AbstractValidateAttribute), true)) //查找属性有没有被定义AbstractValidateAttribute特性 { object objValue = property.GetValue(t);//获取属性的值 foreach (AbstractValidateAttribute attribute in property.GetCustomAttributes(typeof(AbstractValidateAttribute), true)) { if (!attribute.Validate(objValue))//如果成功了以后就继续验证,否则就直接返回 { return false; } } } } return true; } } }
【4】要验证的实体类,并标记特性
namespace _015_特性.ValidateExtend { public class Student { public int Id { get; set; } [Requried] [StringLength(5,10)] public string StudentName { get; set; } [Requried] [Long(11)] public long PhoneNumber { get; set; } } }
【5】在主程序中调用
Student student = new Student() { Id = 1, PhoneNumber = 186684806622, StudentName = "jason cai" }; if (student.Validate()) { Console.WriteLine("验证成功"); } else { Console.WriteLine("验证失败"); }