C# 利用特性(Attribute)实现通用实体类数据合法校验

用过asp.net mvc 的都应该知道,在实体类上添加一些特性,可以实现后端实体的数据校验,这里简单实现一下

实现原理:利用反射获取实体的每一个属性,并通过属性获取属性上标注的特性,调用特性的Validate方法(此方法自定义的)来验证属性的值是否合法。

1、创建自己的校验特性基类

此类继承了Attribute,表明为一个特性,Validate方法为抽象方法,目的是给实现的子类自己定义自己的Validate方法。error为错误消息提示信息。

1 [AttributeUsage(AttributeTargets.Property,AllowMultiple = true)]
2     public abstract class BaseAttribute:Attribute
3     {
4         public virtual string error { get; set; }
5         public abstract bool Validate(object value);
6     }

2、创建特性类继承自BaseAttribute

这里只简单写3个特性,写法都一样,只是校验方法Validate中的逻辑不一样。

复制代码
 1 /// <summary>
 2     /// 约束属性不能为空
 3     /// </summary>
 4     public class RequiredAttribute : BaseAttribute
 5     {
 6         public override string error {
 7             get
 8             {
 9                 if (base.error != null)
10                 {
11                     return base.error;
12                 }
13                 return "属性不能为空";
14             }
15             set => base.error = value;
16         }
17         public override bool Validate(object value)
18         {
19             return !(value == null);
20         }
21     }
复制代码
复制代码
 1 /// <summary>
 2     /// 约束字符串的长度范围
 3     /// </summary>
 4     public class StringRangeAttribute : BaseAttribute
 5     {
 6         public int min { get; set; }
 7         public int max { get; set; }
 8         public override string error {
 9             get {
10                 if (base.error != null)
11                 {
12                     return base.error;
13                 }
14                 return $"字符串长度范围{this.min}-{this.max}";
15             }
16             set => base.error = value; }
17         public override bool Validate(object value)
18         {
19             return value.ToString().Length >= this.min && value.ToString().Length <= this.max;
20         }
21     }
复制代码
复制代码
 1 /// <summary>
 2     /// 约束符合正则表达式
 3     /// </summary>
 4     public class RegexAttribute : BaseAttribute
 5     {
 6         public string regexText;
 7         public override bool Validate(object value)
 8         {
 9             var regex = new Regex(regexText);
10             return regex.Match(value.ToString()).Success;
11         }
12     }
复制代码

3、给实体类扩展一个方法,用来验证实体类实例属性值是否合法

此方式的扩展方法会污染其他非实体类,不是太推荐用太多此种扩展写法,其实这里不写成扩展方法也没什么问题。

此扩展方法会验证实例中的所有属性,并将所有不通过验证的属性的提示信息以字符串的形式返回,所有都验证通过则返回空串。

复制代码
 1 public static string Validate<T>(this T t)
 2         {
 3             Type type = t.GetType();
 4 
 5             //获取所有属性
 6             PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
 7             List<string> errorList = new List<string>();
 8             foreach (PropertyInfo propertyInfo in propertyInfos)
 9             {
10                 if(propertyInfo.IsDefined(typeof(BaseAttribute)))//如果属性上有定义该属性,此步没有构造出实例
11                 {
12                     foreach (BaseAttribute attribute in propertyInfo.GetCustomAttributes(typeof(BaseAttribute)))
13                     {
14                         if (!attribute.Validate(propertyInfo.GetValue(t, null)))
15                         {
16                             errorList.Add( $"[{propertyInfo.Name}]" + attribute.error);
17                         }
18                     }
19                     
20                 }
21             }
22             return string.Join(",", errorList);
23         }
复制代码

4、定义一个实体类,并测试(控制台程序)。

假设有Student.cs ,在其id属性中添加Required特性,name属性上添加StringRange和Regex特性。

1 public class Student
2     {
3         [Required(error = "id 不能为空!")]
4         public int? id { get; set; }
5         [Regex(regexText = "^a.*a$",error = "属性不合格规则")]
6         [StringRange(min =5,max =10)]
7         public string name { get; set; }
8     }
复制代码
 1 static void Main(string[] args)
 2         {
 3             Student student = new Student()
 4             {
 5                 id = null,
 6                 name = "ajiudsagasgasgaxb"
 7             };
 8             string errorStr = student.Validate();
 9             Console.WriteLine(errorStr);
10             Console.ReadKey();
11         }
复制代码

测试结果

 

此代码纯属自己理解的原理性还原,代码可能有多处写的不严谨。

posted @   酒香逢  阅读(6140)  评论(1编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示