zoukankan      html  css  js  c++  java
  • C# System.Attribute(验证类)

    本文以一个项目中通用的验证类来举例说明如何使用自定义Attribute来扩展元数据。

     在项目中,我们为了保证各个层次之间的松藕合,通常把在各个层次之间传递数据的封装在一个称为实体类的类中,比如ActionFrom

    [csharp] view plaincopy
     
    1. using System;  
    2.   
    3. namespace AttributeTest  
    4. {  
    5.     public class ActionForm  
    6.     {  
    7.         private string email = "";  
    8.         private string password = "";  
    9.         public string Email  
    10.         {  
    11.             get { return this.email; }  
    12.             set { this.email = value; }  
    13.         }  
    14.         public string Password  
    15.         {  
    16.             get { return this.password; }  
    17.             set { this.password = value; }  
    18.         }  
    19.   
    20.     }  
    21. }  

    现在,在使用这些实体类中的数据之前,我们需要对其中的数据进行验证。通常我们会写个静态类,用来提供各种不同的验证方法。比如需要验证Email,验证Password,比如:

    [csharp] view plaincopy
     
    1. using System;  
    2. using System.Reflection;  
    3. using System.Text.RegularExpressions;  
    4.   
    5. namespace AttributeTest  
    6. {  
    7.     public class Validator  
    8.     {  
    9.         public static bool ValidateEmail(string email)  
    10.         {  
    11.             //方法体  
    12.         }  
    13.   
    14.         public static bool ValidatePassword(string passwd)  
    15.         {  
    16.             //方法体  
    17.         }  
    18.     }  
    19. }  

    这样的硬编码混迹于各个层次之间,一旦实体类里某个属性发生变化,就不得不修改各个层次中的相关验证代码。于是,我们想到可以使用一个统一的验证方法用来验证所有的实体类中的属性。

    [csharp] view plaincopy
     
    1. public static bool Validate(string propertyName, string propertyValue, Validator.ValidateType t) {...}  

    这里,Validator.ValidateType 是Validator中提供的一个枚举。

    [csharp] view plaincopy
     
    1. public enum ValidateType  
    2.    {  
    3.        Email,  
    4.        Password,  
    5.        Number,  
    6.        Id  
    7.    }  

    这里这个验证方法,的第三个参数使得验证与实体类的耦合密度增加了。我们还是不得不在修改实体类的时候,修改验证方法的调用代码。

    现在,我们需要自定义Attribute来扩展实体类的元数据。通过对实体类元数据的描述,我们可以去掉验证方法里的第三个参数

    [csharp] view plaincopy
     
    1. using System;  
    2. namespace AttributeTest  
    3. {  
    4.     [System.AttributeUsage(AttributeTargets.Property)]  
    5.     public class ValidateAttribute : System.Attribute  
    6.     {  
    7.         public ValidateAttribute(ValidateType validateType)  
    8.         {  
    9.             this.validateType = validateType;  
    10.         }  
    11.         private ValidateType validateType;  
    12.   
    13.         public ValidateType ValidateType  
    14.         {  
    15.             get { return this.validateType; }  
    16.             set { this.validateType = value; }  
    17.         }  
    18.     }  
    19.     public enum ValidateType  
    20.     {  
    21.         Email,  
    22.         Password,  
    23.         Number,  
    24.         Id  
    25.     }  
    26. }  

    自定义Attribute(特性)必须继承于System.Attribute。还可以通过System.AttributeUsageAttribute特性,控制自定义特性的使用范围(构件),例如,字段、方法。[System.AttributeUsage(AttributeTargets.Property)]限制这个自定义特性只能使用在类的属性上。

    现在,我们实现这个验证方法:

    [csharp] view plaincopy
     
    1. using System;  
    2. using System.Reflection;  
    3. using System.Text.RegularExpressions;  
    4.   
    5. namespace AttributeTest  
    6. {  
    7.     public class Validator  
    8.     {  
    9.         public static bool Validate(object validateObject, string validateProperty)  
    10.         {  
    11.             System.Type t = validateObject.GetType();  
    12.             PropertyInfo pi = t.GetProperty(validateProperty);  
    13.   
    14.             string validateValue = pi.GetValue(validateObject, null) as string;  
    15.   
    16.             if (pi.IsDefined(typeof(ValidateAttribute), true))  
    17.             {  
    18.                 object[] atts = pi.GetCustomAttributes(true);  
    19.                 ValidateAttribute vatt = atts[0] as ValidateAttribute;  
    20.                 string strExpr = "";  
    21.                 switch (vatt.ValidateType)  
    22.                 {  
    23.                     case ValidateType.Email:  
    24.                         strExpr = @"^[w-]+(.[w-]+)*@[w-]+(.[w-]+)+{1}quot;;  
    25.                         break;  
    26.                     case ValidateType.Password:  
    27.                         strExpr = @"d{6}";  
    28.                         break;  
    29.                     case ValidateType.Number:  
    30.                         strExpr = @"^d*{1}quot;;  
    31.                         break;  
    32.                     case ValidateType.Id:  
    33.                         strExpr = @"^w*{1}quot;;  
    34.                         break;  
    35.                     default:  
    36.                         return true;  
    37.                 }  
    38.                 Regex validateRegex = new Regex(strExpr);  
    39.                 return validateRegex.IsMatch(validateValue);  
    40.             }  
    41.             return true;  
    42.         }  
    43.     }  
    44. }  

    该方法需要两个参数,一个是需要验证的实体类的实例,还有一个是需要验证的属性名。当然,我们还需要在实体类上加上我们自定义的特性:

    [csharp] view plaincopy
     
    1. using System;  
    2.   
    3. namespace AttributeTest  
    4. {  
    5.     public class ActionForm  
    6.     {  
    7.         private string email = "";  
    8.         private string password = "";  
    9.   
    10.         [Validate(ValidateType.Email)]  
    11.         public string Email  
    12.         {  
    13.             get { return this.email; }  
    14.             set { this.email = value; }  
    15.         }  
    16.   
    17.         [Validate(ValidateType.Password)]  
    18.         public string Password  
    19.         {  
    20.             get { return this.password; }  
    21.             set { this.password = value; }  
    22.         }  
    23.   
    24.     }  
    25. }  
    
    

    我们通过自定义特性对实体类的元数据进行扩展,指定每个属性需要验证的类型。

    现在我们可以这样使用这个验证类:

    [csharp] view plaincopy
     
    1. ActionForm form = new ActionForm();  
    2. form.Email = justacoder@123.com;  
    3. form.Password = "123456";  
    4.   
    5. bool isValidEmail = Validator.Validate(form, "Email");  
    6. bool isValidPassword = Validator.Validate(form, "Password");  
    7.   
    8. Console.WriteLine("Email is {0}.", isValidEmail?"valid":"invalid");  
    9. Console.WriteLine("Password is {0}.", isValidPassword?"valid":"invalid");  
    10.   
    11. Console.ReadLine();  

    我们通过抛出自定义异常的方法,将验证扩大到实体类级别的验证:

    [csharp] view plaincopy
     
    1. public static void ValidateProperty(object validateObject, string validateProperty)  
    2.   {  
    3.    System.Type t = validateObject.GetType();  
    4.    PropertyInfo pi = t.GetProperty(validateProperty);  
    5.      
    6.    string validateValue = pi.GetValue(validateObject, null) as string;  
    7.      
    8.    if( pi.IsDefined(typeof(ValidateAttribute), true) )  
    9.    {  
    10.     object[] atts = pi.GetCustomAttributes(true);  
    11.     ValidateAttribute vatt = atts[0] as ValidateAttribute;  
    12.     string strExpr = "";  
    13.     switch(vatt.ValidateType)  
    14.     {  
    15.      case ValidateType.Email:  
    16.       strExpr = @"^[w-]+(.[w-]+)*@[w-]+(.[w-]+)+{1}quot;;  
    17.       break;  
    18.      case ValidateType.Password:  
    19.       strExpr = @"d{6}";  
    20.       break;  
    21.      case ValidateType.Number:  
    22.       strExpr = @"^d*{1}quot;;  
    23.       break;  
    24.      case ValidateType.Id:  
    25.       strExpr = @"^w*{1}quot;;  
    26.       break;  
    27.      default:  
    28.       return;       
    29.     }  
    30.     Regex validateRegex = new Regex(strExpr);  
    31.     if( !validateRegex.IsMatch(validateValue) )  
    32.     {  
    33.         throw new ApplicationException(validateProperty + " is invalid.");  
    34.     }  
    35.    }  
    36.   }  
    37.   
    38.   public static void Validate(object validateObject)  
    39.   {  
    40.       System.Type t = validateObject.GetType();  
    41.             PropertyInfo[] ps = t.GetProperties();  
    42.   
    43.    foreach(PropertyInfo pi in ps)  
    44.    {  
    45.        ValidateProperty(validateObject, pi.Name);  
    46.    }  
    47.   }  

    现在验证,只需要这样:

    [csharp] view plaincopy
     
    1. try  
    2. {  
    3.    Validator.Validate(form);  
    4. }  
    5. catch(Exception ex)  
  • 相关阅读:
    java 项目自我总结-01 开发环境的搭建
    sql server 导入c#dll
    java 开发自我总结- idea 如何打包spring boot
    如何快速创建多工作页 excel
    运维知识总结
    .net core
    ubuntu安装网易云音乐
    Java中(==)与equals的区别
    Linux压缩打包命令
    文件目录属性
  • 原文地址:https://www.cnblogs.com/Alex80/p/4373042.html
Copyright © 2011-2022 走看看