五维思考

学习要加,骄傲要减,机会要乘,懒惰要除。 http://www.5dthink.cn

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

实现原理:利用反射获取实体的每一个属性,并通过属性获取属性上标注的特性,调用特性的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属性上添加LengthRegex特性。

    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
posted on 2015-03-06 07:22  五维思考  阅读(472)  评论(0编辑  收藏  举报

QQ群:1. 全栈码农【346906288】2. VBA/VSTO【2660245】