前言
Attribute(特性)的概念不在此赘述了,相信有点.NET基础的开发人员都明白,用过Attribute的人也不在少数,毕竟很多框架都提供自定义的属性,类似于Newtonsoft.JSON中JsonProperty、JsonIgnore等
自定义特性
.NET 框架允许创建自定义特性,用于存储声明性的信息,且可在运行时被检索。该信息根据设计标准和应用程序需要,可与任何目标元素相关。
创建并使用自定义特性包含四个步骤:
- 声明自定义特性
- 构建自定义特性
- 在目标程序元素上应用自定义特性
- 通过反射访问特性
声明自定义特性
一个新的自定义特性必须派生自System.Attribute类,例如:
public class FieldDescriptionAttribute : Attribute { public string Description { get; private set; } public FieldDescriptionAttribute(string description) { Description = description; } }
public class UserEntity { [FieldDescription("用户名称")] public string Name { get; set; } }
该如何拿到我们标注的信息呢?这时候需要使用反射获取
var type = typeof(UserEntity); var properties = type.GetProperties(); foreach (var item in properties) { if(item.IsDefined(typeof(FieldDescriptionAttribute), true)) { var attribute = item.GetCustomAttribute(typeof(FieldDescriptionAttribute)) as FieldDescriptionAttribute; Console.WriteLine(attribute.Description); } }
执行结果如下:
从执行结果上看,我们拿到了我们想要的数据,那么这个特性在实际使用过程中,到底有什么用途呢?
Attribute特性妙用
在实际开发过程中,我们的系统总会提供各种各样的对外接口,其中参数的校验是必不可少的一个环节。然而没有特性时,校验的代码是这样的:
public class UserEntity { /// <summary> /// 姓名 /// </summary> [FieldDescription("用户名称")] public string Name { get; set; } /// <summary> /// 年龄 /// </summary> public int Age { get; set; } /// <summary> /// 地址 /// </summary> public string Address { get; set; } }
UserEntity user = new UserEntity(); if (string.IsNullOrWhiteSpace(user.Name)) { throw new Exception("姓名不能为空"); } if (user.Age <= 0) { throw new Exception("年龄不合法"); } if (string.IsNullOrWhiteSpace(user.Address)) { throw new Exception("地址不能为空"); }
字段多了之后这种代码就看着非常繁琐,并且看上去不直观。对于这种繁琐又恶心的代码,有什么方法可以优化呢?
使用特性后的验证写法如下:
首先定义一个基础的校验属性,提供基础的校验方法
public abstract class AbstractCustomAttribute : Attribute { /// <summary> /// 校验后的错误信息 /// </summary> public string ErrorMessage { get; set; } /// <summary> /// 数据校验 /// </summary> /// <param name="value"></param> public abstract void Validate(object value); }
然后可以定义常用的一些对应的校验Attribute,例如RequiredAttribute、StringLengthAttribute
/// <summary> /// 非空校验 /// </summary> [AttributeUsage(AttributeTargets.Property)] public class RequiredAttribute : AbstractCustomAttribute { public override void Validate(object value) { if (value == null || string.IsNullOrWhiteSpace(value.ToString())) { throw new Exception(string.IsNullOrWhiteSpace(ErrorMessage) "字段不能为空" : ErrorMessage); } } } /// <summary> /// 自定义验证,验证字符长度 /// </summary> [AttributeUsage(AttributeTargets.Property)] public class StringLengthAttribute : AbstractCustomAttribute { private int _maxLength; private int _minLength; public StringLengthAttribute(int minLength, int maxLength) { this._maxLength = maxLength; this._minLength = minLength; } public override void Validate(object value) { if (value != null && value.ToString().Length >= _minLength && value.ToString().Length <= _maxLength) { return; } throw new Exception(string.IsNullOrWhiteSpace(ErrorMessage) "字段长度必须在{_minLength}与{_maxLength}之间" : ErrorMessage); } }
添加一个用于校验的ValidateExtensions
public static class ValidateExtensions { /// <summary> /// 校验 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static void Validate<T>(this T entity) where T : class { Type type = entity.GetType(); foreach (var item in type.GetProperties()) { //需要对Property的字段类型做区分处理针对Object List 数组需要做区分处理 if (item.PropertyType.IsPrimitive || item.PropertyType.IsEnum || item.PropertyType.IsValueType || item.PropertyType == typeof(string)) { //如果是基元类型、枚举类型、值类型或者字符串 直接进行校验 CheckProperty(entity, item); } else { //如果是引用类型 var value = item.GetValue(entity, null); CheckProperty(entity, item); if (value != null) { if ((item.PropertyType.IsGenericType && Array.Exists(item.PropertyType.GetInterfaces(), t => t.GetGenericTypeDefinition() == typeof(IList<>))) || item.PropertyType.IsArray) { //判断IEnumerable var enumeratorMI = item.PropertyType.GetMethod("GetEnumerator"); var enumerator = enumeratorMI.Invoke(value, null); var moveNextMI = enumerator.GetType().GetMethod("MoveNext"); var currentMI = enumerator.GetType().GetProperty("Current"); int index = 0; while (Convert.ToBoolean(moveNextMI.Invoke(enumerator, null))) { var currentElement = currentMI.GetValue(enumerator, null); if (currentElement != null) { currentElement.Validate(); } index++; } } else { value.Validate(); } } } } } private static void CheckProperty(object entity, PropertyInfo property) { if (property.IsDefined(typeof(AbstractCustomAttribute), true))//此处是重点 { //此处是重点 foreach (AbstractCustomAttribute attribute in property.GetCustomAttributes(typeof(AbstractCustomAttribute), true)) { if (attribute == null) { throw new Exception("AbstractCustomAttribute not instantiate"); } attribute.Validate(property.GetValue(entity, null)); } } } }
新的实体类
public class UserEntity { /// <summary> /// 姓名 /// </summary> [Required] public string Name { get; set; } /// <summary> /// 年龄 /// </summary> public int Age { get; set; } /// <summary> /// 地址 /// </summary> [Required] public string Address { get; set; } [StringLength(11, 11)] public string PhoneNum { get; set; } }
调用方式
UserEntity user = new UserEntity(); user.Validate();
上面的校验逻辑写的比较复杂,主要是考虑到对象中包含复杂对象的情况,如果都是简单对象,可以不用考虑,只需针对单个属性做字段校验
现有的方式是在校验不通过的时候抛出异常,此处大家也可以自定义异常来表示校验的问题,也可以返回自定义的校验结果实体来记录当前是哪个字段出的问题,留待大家自己实现
如果您有更好的建议和想法欢迎提出,共同进步
总结
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 古典吉他《鲁特琴-BachInspirations巴赫灵感》ThibautGarcia[24Bit/96kHz]
- 刘纬武《睡眠音乐家 缓解疼痛 赫兹白噪音》[320K/MP3][217.2MB]
- 刘纬武《睡眠音乐家 缓解疼痛 赫兹白噪音》[FLAC/分轨][870.69MB]
- 群星1998 《宝丽金最佳电视主题曲》香港首版[WAV+CUE][1.2G]
- 群星1990《群星会·金曲重现》新加坡版[WAV+CUE][1.1G]
- 张惠妹2003《勇敢》[WAV+CUE][1.1G]
- 群星1995《摇滚中国乐势力》首版引进版[WAV+CUE][983M]
- 陈思安《32首酒廊情调》2CD新雅(国际)影碟[WAV+CUE]
- 齐豫潘越云《回声》K2HD[正版原抓WAV+CUE]
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]