• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

.Net —— 深入理解"特性"(3)手撸特性提供额外行为,如:字段数据验证

互联网 diligentman 2周前 (01-11) 10次浏览

开发项目过程中,导出都需要数据验证,接下来我们写一个实例,通过特性实现对我们项目中关于数据的验证,比如:对手机号、密码、邮箱等的非空、格式的验证行为等。

如果在没有特性支持的情况下,我们只能通过对每个字段if-else,正则等挨个进行验证,当然我们也可以抽象方法,可扩展性不好,对于架构而言是致命的。

为了更好的组织代码,我先创建了一个ValidateExtend文件夹来存放验证规则扩展特性。接下来直接上代码。

1 字段不能为空实现

1.1 创建RequireAttribute特性

    [AttributeUsage(AttributeTargets.Property)]
    public class RequireAttribute : Attribute
    {
        /// <summary>
        /// 提示错误信息
        /// </summary>
        public string ErrorMessage { get; set; }
        public RequireAttribute() { }


        public override bool Validate(object oValue)
        {
            return oValue != null && oValue.ToString().Trim() != "";
        }
    }

1.2 创建扩展验证类AttributeExtend,用于调用验证,由于我创建了独立的验证规则ValidateExtend文件夹,因此不跟以前的命名空间冲突,是个全新的。此处注意我将类定为static静态类、静态方法以及参数中的this关键字,在调用时非常的方便!!!

    public static class AttributeExtend
    {
        public static bool Validate<T>(this T t)
        {
            Type type = t.GetType();
            foreach (var prop in type.GetProperties())
            {
                if (prop.IsDefined(typeof(RequireAttribute), true))
                {

                    RequireAttribute ra = (RequireAttribute)prop.GetCustomAttribute(typeof(RequireAttribute), true);
                    return ra.Validate(prop.GetValue(t));

                }
            }
            return true;
        }
    }

1.3 为属性新增特性,请注意Show防范中的调用方法,1.2中的写法就可以实现如下调用,当然,也可以在其他地方调用。

    public class UserModel
    {    
        [Require(ErrorMessage = "昵称不能为空")]
        public string NickName { get; set; }

        public void Show()
        {
            Console.WriteLine($"昵称:{this.NickName}");
            // 执行规则验证,注意此处调用方法
            Console.WriteLine($"规则验证是否通过:{this.Validate()}");
        }
    }

1.4 验证

    class Program
    {
        static void Main(string[] args)
        {
            UserModel um = new UserModel() 
            { 
                // NickName = "十三点"  //将昵称注释,不赋值
            };
            um.Show();
        }
    }

.Net —— 深入理解"特性"(3)手撸特性提供额外行为,如:字段数据验证

 

2 升级规则验证,新增多种规则验证

2.1 为了方便处理返回消息,先抽象出一个验证结果集ValidateResult类

    /// <summary>
    /// 验证规则结果集
    /// </summary>
    public class ValidateResult
    {
        /// <summary>
        /// 是否通过验证
        /// </summary>
        public bool IsValidate = true;
        /// <summary>
        /// 返回错误消息列表
        /// </summary>
        public List<string> Messages = new List<string>();
    }

2.2 考虑到将会有很多的特性处理,且调用时都需要调用不同的特性中的“验证”方法,因此,抽象出一个父级特性ValidateAttribute。

    /// <summary>
    /// 验证特性父级
    /// </summary>
    [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
    public abstract class ValidateAttribute : Attribute
    {
        public ValidateAttribute() { }
        /// <summary>
        /// 错误信息
        /// </summary>
        public string ErrorMessage { get; set; }
        /// <summary>
        /// 执行验证
        /// </summary>
        /// <param name="oValue">需要验证的特性字段</param>
        /// <returns></returns>
        public abstract bool Validate(object oValue);
    }

2.3 修改原有不能为空特性验证类,继承ValidateAttribute。

    /// <summary>
    /// 为空验证约定
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class RequireAttribute : ValidateAttribute
    {
        public RequireAttribute() { }
        public override bool Validate(object oValue)
        {
            return oValue != null && !string.IsNullOrEmpty(oValue.ToString().Trim());
        }
    }

2.4 新增字符串长度规则特性,Length,可用于判断密码长度等

    /// <summary>
    /// 验证字符长度是否符合设定长度
    /// 默认6-20
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class LengthAttribute : ValidateAttribute
    {
        private int Min = 6;
        private int Max = 20;

        public LengthAttribute() { }
        public LengthAttribute(int minLength, int maxLength)
        {
            this.Min = minLength;
            this.Max = maxLength;
        }

        public override bool Validate(object oValue)
        {
            if (oValue == null) return false;
            return Validate(oValue.ToString());
        }

        public bool Validate(string oValue)
        {
            return oValue.Length >= Min && oValue.Length <= Max;
        }
    }

2.5 改进AttributeExtend扩展类

    public static class AttributeExtend
    {
        public static ValidateResult Validate<T>(this T t)
        {
            ValidateResult res = new ValidateResult();
            Type type = t.GetType();
            foreach (var prop in type.GetProperties())
            {
                if (prop.IsDefined(typeof(ValidateAttribute), true))
                {
                    // 此处需要验证所有使用了验证规则特性的属性
                    foreach (var item in prop.GetCustomAttributes(typeof(ValidateAttribute), true))
                    {
                        ValidateAttribute validateAttribute = (ValidateAttribute)item;
                        if (!validateAttribute.Validate(prop.GetValue(t)))
                        {
                            res.IsValidate = false;
                            res.Messages.Add(
                                string.IsNullOrEmpty(validateAttribute.ErrorMessage) ? 
                                    $"请检查{prop.Name}参数赋值情况" : validateAttribute.ErrorMessage
                                );
                            // 一个属性多个规则条件下,每个属性只判断一次规则
                            break;
                        }
                    }
                }
            }
            return res;
        }
    }

2.6 在实体中使用验证特性

    public class UserModel : ModelBase
    {
        public int Id { get; set; }
        [Require(ErrorMessage = "昵称不能为空")]
        public string NickName { get; set; }
        /// <summary>
        /// 用户状态
        /// </summary>
        public UserState UserState { get; set; }

        /// <summary>
        /// 密码
        /// </summary>
        [Require(ErrorMessage = "密码不能为空")]
        [Length(6, 12, ErrorMessage = "密码长度必须为6-12个字")]
        public string Password { get; set; }

        [Long(10000,999999999999,ErrorMessage = "QQ长度不符")]
        public long QQ { get; set; }


        public void Show()
        {
            Console.WriteLine($"ID:{this.Id} - {this.Id}");
            Console.WriteLine($"昵称:{this.NickName}");
            Console.WriteLine($"QQ:{this.QQ}");

            ValidateResult vr = this.Validate();
            Console.WriteLine(string.Format("规则验证:{0}", vr.IsValidate ? "通过" : "不通过"));
            foreach (var item in vr.Messages)
            {
                Console.WriteLine($"{item}");
            }

        }
    }

2.7 验证

    class Program
    {
        static void Main(string[] args)
        {
            UserModel um = new UserModel() { Id = 1, Password ="123", QQ = 1111 };
            um.Show();
        }
    }

.Net —— 深入理解"特性"(3)手撸特性提供额外行为,如:字段数据验证

 

 

OK,欢迎吐槽~

 

特性系列:

.Net —— 深入理解”特性”(1)源码解读 https://my.oschina.net/berzhuan/blog/4882044&nbsp;

.Net —— 深入理解”特性”(2)手撸特性提供额外属性,如:状态描述、对象与数据库及字段绑定等 https://my.oschina.net/berzhuan/blog/4890289

.Net —— 深入理解”特性”(3)手撸特性提供额外行为,如:字段数据验证 https://my.oschina.net/berzhuan/blog/4890290

{{o.name}}


{{m.name}}


喜欢 (0)