鹰潭旅游景点大全:.NET Attribute在数据校验上的应用

admin 3个月前 (06-14) 科技 36 1

Attribute(特征)的观点不在此赘述了,赖有点.NET基础的开发人员都明了,用过Attribute的人也不在少数,究竟许多框架都提供自界说的属性,类似于NewtoNSoft.JSON中JsonProperty、JsonI.Nore等

自界说特征

.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 &amp;& 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();

上面的校验逻辑写的比较庞大,主要是思量到工具中包罗庞大工具的情形,若是都是简朴工具,可以不用思量,只需针对单个属性做字段校验
现有的方式是在校验不通过的时刻抛出异常,此处人人也可以自界说异常来示意校验的问题,也可以返回自界说的校验效果实体来纪录当前是哪个字段出的问题,留待人人自己实现
若是您有更好的建媾和想法迎接提出,共同进步

以上代码均为原创分享,若人人认为有不妥的地方,烦请留言指出,在下感激涕零

本文作者:hexuwsbg

出处:https://www.cNBlogs.com/hexu0512/p/12879671.html

版权:本文接纳「可附带出处转载」知识共享允许协议举行允许

,

诚信在线

诚信在线(www.cX11gw.cn)现已开放诚信在线手机版下载。游戏公平、公开、公正,用实力赢取信誉。

Sunbet声明:该文看法仅代表作者自己,与本平台无关。转载请注明:鹰潭旅游景点大全:.NET Attribute在数据校验上的应用

网友评论

  • (*)

最新评论

  • ALLBET官网官方注册 2020-06-14 00:04:52 回复

    欧博手机版下载欢迎进入欧博手机版下载(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。悄悄走过~

    1

站点信息

  • 文章总数:950
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1967
  • 评论总数:52
  • 浏览总数:5308