实现原理:利用反射获取实体的每一个属性,并通过属性获取属性上标注的特性,调用特性的Validate
方法(此方法自定义的)来验证属性的值是否合法。
1、创建基类
创建校验特性的基类BaseAttribute
,该类继承了Attribute
表明为一个特性,Validate
方法为抽象方法,目的是给实现的子类自己定义自己的Validate
方法。error
为错误消息提示信息。
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public abstract class BaseAttribute : Attribute
{
public virtual string error { get; set; }
public abstract bool Validate(object value);
}
2、创建特性类
这里只简单写3个特性,写法都一样,只是校验方法Validate
中的逻辑不一样。
/// <summary>
/// 约束字符串的长度范围
/// </summary>
public class LengthAttribute : BaseAttribute
{
public int min { get; set; }
public int max { get; set; }
public override string error
{
get
{
if (!string.IsNullOrEmpty(base.error))
{
return base.error;
}
return $"字符串长度应为{min}~{max}";
}
set => base.error = value;
}
public override bool Validate(object value)
{
return value.ToString().Length >= min && value.ToString().Length <= max;
}
}
/// <summary>
/// 约束属性不能为空
/// </summary>
public class RequiredAttribute : BaseAttribute
{
public override string error
{
get
{
if (base.error != null)
{
return base.error;
}
return "属性不能为空";
}
set => base.error = value;
}
public override bool Validate(object value)
{
return !(value == null);
}
}
/// <summary>
/// 约束符合正则表达式
/// </summary>
public class RegexAttribute : BaseAttribute
{
public string pattern;
public override bool Validate(object value)
{
var regex = new Regex(pattern);
return regex.Match(value.ToString()).Success;
}
}
3、数据验证
给实体类扩展一个方法,用来验证实体类实例属性值是否合法。此方式的扩展方法会污染其他非实体类,不是太推荐用太多此种扩展写法,其实这里不写成扩展方法也没什么问题。此扩展方法会验证实例中的所有属性,并将所有不通过验证的属性的提示信息以字符串的形式返回,所有都验证通过则返回空串。
public static class MyExtends
{
/// <summary>
/// 验证实体类实例属性值是否合法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static string Validate<T>(this T t) where T : class
{
Type type = t.GetType();
//获取所有属性
PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
List<string> errorList = new List<string>();
foreach (PropertyInfo propertyInfo in propertyInfos)
{
if (propertyInfo.IsDefined(typeof(BaseAttribute)))//如果属性上有定义该属性,此步没有构造出实例
{
foreach (BaseAttribute attribute in propertyInfo.GetCustomAttributes(typeof(BaseAttribute)))
{
if (!attribute.Validate(propertyInfo.GetValue(t)))
{
errorList.Add($"[{propertyInfo.Name}]" + attribute.error);
}
}
}
}
return string.Join(",", errorList);
}
}
4、功能测试
创建测试类StudentTest.cs
,在其id
属性中添加Required
特性,name
属性上添加Length
和Regex
特性。
public class StudentTest
{
[Required(error ="不能为空")]
public int? Id { get; set; }
[Regex(pattern =@"^s\w*$",error ="不符合命名规则")]
[Length(min =3, max =6)]
public string Name { get; set; }
public int Age { get; set; }
}
控制台程序:
static void Main(string[] args)
{
StudentTest student = new StudentTest() { Name="ab" };
Console.WriteLine($"{student.Validate()}");
Console.Read();
}
输出结果:
[Id]不能为空,[Name]不符合命名规则,[Name]字符串长度应为3~6