本文以一个项目中通用的验证类来举例说明如何使用自定义Attribute来扩展元数据。
在项目中,我们为了保证各个层次之间的松藕合,通常把在各个层次之间传递数据的封装在一个称为实体类的类中,比如ActionFrom
using System;
namespace AttributeTest
{
public class ActionForm
{
private string email = "";
private string password = "";
public string Email
{
get{return this.email;}
set{this.email = value;}
}
public string Password
{
get{ return this.password;}
set{ this.password = value;}
}
}
}
现在,在使用这些实体类中的数据之前,我们需要对其中的数据进行验证。通常我们会写个静态类,用来提供各种不同的验证方法。比如需要验证Email,验证Password,比如:
using System;
using System.Reflection;
using System.Text.RegularExpressions;
namespace AttributeTest
{
public class Validator
{
public static bool ValidateEmail(string email) {...}
public static bool ValidatePassword(string passwd) {...}
}
}
这样的硬编码混迹于各个层次之间,一旦实体类里某个属性发生变化,就不得不修改各个层次中的相关验证代码。于是,我们想到可以使用一个统一的验证方法用来验证所有的实体类中的属性。
public static bool Validate(string propertyName, string propertyValue, Validator.ValidateType t) {...}
这里,Validator.ValidateType 是Validator中提供的一个枚举。
public enum ValidateType
{
Email,
Password,
Number,
Id
}
这里这个验证方法,的第三个参数使得验证与实体类的耦合密度增加了。我们还是不得不在修改实体类的时候,修改验证方法的调用代码。
现在,我们需要自定义Attribute来扩展实体类的元数据。通过对实体类元数据的描述,我们可以去掉验证方法里的第三个参数。
using System;
namespace AttributeTest
{
[System.AttributeUsage(AttributeTargets.Property)]
public class ValidateAttribute : System.Attribute
{
public ValidateAttribute(ValidateType validateType)
{
this.validateType = validateType;
}
private ValidateType validateType;
public ValidateType ValidateType
{
get{ return this.validateType; }
set{ this.validateType = value; }
}
}
public enum ValidateType
{
Email,
Password,
Number,
Id
}
}
自定义Attribute(特性)必须继承于System.Attribute。还可以通过System.AttributeUsageAttribute特性,控制自定义特性的使用范围(构件),例如,字段、方法。[System.AttributeUsage(AttributeTargets.Property)]限制这个自定义特性只能使用在类的属性上。
现在,我们实现这个验证方法:
using System;
using System.Reflection;
using System.Text.RegularExpressions;
namespace AttributeTest
{
public class Validator
{
public static bool Validate(object validateObject, string validateProperty)
{
System.Type t = validateObject.GetType();
PropertyInfo pi = t.GetProperty(validateProperty);
string validateValue = pi.GetValue(validateObject, null) as string;
if( pi.IsDefined(typeof(ValidateAttribute), true) )
{
object[] atts = pi.GetCustomAttributes(true);
ValidateAttribute vatt = atts[0] as ValidateAttribute;
string strExpr = "";
switch(vatt.ValidateType)
{
case ValidateType.Email:
strExpr = @"^[/w-]+(/.[/w-]+)*@[/w-]+(/.[/w-]+)+$";
break;
case ValidateType.Password:
strExpr = @"/d{6}";
break;
case ValidateType.Number:
strExpr = @"^/d*$";
break;
case ValidateType.Id:
strExpr = @"^/w*$";
break;
default:
return true;
}
Regex validateRegex = new Regex(strExpr);
return validateRegex.IsMatch(validateValue);
}
return true;
}
}
}
该方法需要两个参数,一个是需要验证的实体类的实例,还有一个是需要验证的属性名。当然,我们还需要在实体类上加上我们自定义的特性:
using System;
namespace AttributeTest
{
public class ActionForm
{
private string email = "";
private string password = "";
[Validate(ValidateType.Email)]
public string Email
{
get{return this.email;}
set{this.email = value;}
}
[Validate(ValidateType.Password)]
public string Password
{
get{return this.password;}
set {this.password = value;}
}
}
}
我们通过自定义特性对实体类的元数据进行扩展,指定每个属性需要验证的类型。
现在我们可以这样使用这个验证类:
ActionForm form = new ActionForm();
form.Email = justacoder@123.com;
form.Password = "123456";
bool isValidEmail = Validator.Validate(form, "Email");
bool isValidPassword = Validator.Validate(form, "Password");
Console.WriteLine("Email is {0}.", isValidEmail?"valid":"invalid");
Console.WriteLine("Password is {0}.", isValidPassword?"valid":"invalid");
Console.ReadLine();
我们通过抛出自定义异常的方法,将验证扩大到实体类级别的验证:
public static void ValidateProperty(object validateObject, string validateProperty)
{
System.Type t = validateObject.GetType();
PropertyInfo pi = t.GetProperty(validateProperty);
string validateValue = pi.GetValue(validateObject, null) as string;
if( pi.IsDefined(typeof(ValidateAttribute), true) )
{
object[] atts = pi.GetCustomAttributes(true);
ValidateAttribute vatt = atts[0] as ValidateAttribute;
string strExpr = "";
switch(vatt.ValidateType)
{
case ValidateType.Email:
strExpr = @"^[/w-]+(/.[/w-]+)*@[/w-]+(/.[/w-]+)+$";
break;
case ValidateType.Password:
strExpr = @"/d{6}";
break;
case ValidateType.Number:
strExpr = @"^/d*$";
break;
case ValidateType.Id:
strExpr = @"^/w*$";
break;
default:
return;
}
Regex validateRegex = new Regex(strExpr);
if( !validateRegex.IsMatch(validateValue) )
{
throw new ApplicationException(validateProperty + " is invalid.");
}
}
}
public static void Validate(object validateObject)
{
System.Type t = validateObject.GetType();
PropertyInfo[] ps = t.GetProperties();
foreach(PropertyInfo pi in ps)
{
ValidateProperty(validateObject, pi.Name);
}
}
现在验证,只需要这样:
try
{
Validator.Validate(form);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
分享到:
相关推荐
Attribute标记属性在.NET框架中扮演着重要的角色,它是元数据的一部分,允许我们在代码中附加信息,这些信息在程序运行时可以被编译器、运行时或其他工具读取和使用。Attribute提供了一种灵活的方式来注解类、方法、...
在.NET框架中,属性(Attribute)是一种元数据,可以附加到程序元素,如类、方法、属性等,为编译器、运行时环境或其他工具提供额外的信息。它们是编程中的一个重要概念,允许开发者向代码中添加非执行性的描述性...
在.NET框架中,Attribute是一种元数据,用于向编译器、IDE、运行时环境等提供额外的信息。这些信息可以用来修饰类、接口、方法、属性等各种编程元素,从而实现特定的功能或扩展。AOP(面向切面编程)是一种编程范式...
在WinForm应用中,自定义特性(Custom Attributes)是一个非常实用的功能,允许我们为类、方法、属性等编程元素添加元数据,这些元数据可以在运行时被反射机制读取,从而实现各种高级功能。本资源“winform 自定义...
在C#编程语言中,特性(Attribute)是一种元数据,它可以提供有关代码的附加信息,这些信息可以在编译时或运行时被程序访问。特性允许程序员向类、方法、属性等添加自定义标记,以便在后期处理中进行特定操作。另一...
4. **元数据查询**:使用反射API来查找和解析特性信息,如查找所有带有特定特性的类或方法。 通过分析和运行压缩包中的代码,你可以更深入地理解.NET中特性的概念,以及它们在实际开发中的应用。这包括了自定义特性...
Visual Studio 2017是开发C#应用程序的强大工具,它支持对特性(Attribute)的创建和使用,以及通过反射进行元数据的探索。 特性(Attribute)是C#中的一种特殊类,它们以`[ ]`括起来,用于标记程序元素。例如,`...
这涉及到元数据查询、反射和自定义Attribute的使用,这些都是现代.NET开发中的核心概念。 首先,Attributes是.NET框架中一种元数据的声明性方式,用于向编译器和运行时提供额外的信息。开发者可以定义自己的...
类成员的属性是用于读取和设置对象状态的特殊方法,而Attribute则是一种元数据注解,它们在代码中以特定的语法形式存在,通常用方括号包围,如`[Conditional("DEBUG")]`。 Attribute的概念源自于公共语言运行时...
`System.ComponentModel.DataAnnotations`为实体类提供了元数据支持。其中的`DataTypeAttribute`、`DisplayFormatAttribute`、`RangeAttribute`、`RegularExpressionAttribute`、`RequiredAttribute`、`...
在C#编程语言中,特性(Attribute)是一种元数据,它可以提供附加信息到代码的不同元素,如类、方法、属性等。这些元数据在编译时不会直接影响代码的行为,但可以在运行时通过反射机制被程序读取和使用,从而实现...
总结来说,C#的Attribute和Reflection提供了强大的元数据管理和运行时代码操作能力,使得开发者能以灵活的方式实现代码的扩展性和动态性。在实际开发中,熟练掌握这两项技术能够极大地提升代码的可维护性和灵活性。...
C#特性(Attribute)是元数据的一种形式,它允许我们在代码中添加附加信息,这些信息在编译时或运行时可以被编译器、运行时环境或其他工具使用。特性的概念引入,使得开发者能够更灵活地对代码进行注解,为代码提供...
`property`和`attribute`的区别在于,`property`主要用于封装和控制数据访问,而`attribute`则用于提供元数据,增强代码的可扩展性和信息丰富度。结合使用,它们可以使C#代码更具有灵活性、安全性和可维护性。 总结...
- **OperationContact**:描述了操作级别的元数据。 - **CorrelationOperationBehavior**:用于关联不同的服务操作。 - **Service Discovery**:支持服务发现,使客户端能够找到可用的服务。 - **AnnouncementClient...
特性是元数据的一种形式,可以在编译时或运行时为代码添加附加信息。这些信息可以用于验证、序列化、调试或其他自定义逻辑。特性通过在元素声明前加上`[AttributeName]`来应用,如`[Serializable]`、`...
在编程领域,自定义属性(Custom Attributes)是一种强大的机制,允许程序员向代码元素(如类、方法、属性等)添加元数据。这些元数据可以用于各种目的,如文档生成、运行时验证、编译时检查或者实现特定的框架功能...
自定义属性允许程序员扩展元数据,为类、方法、字段和其他程序元素添加额外的信息,这些信息可以被编译器、运行时环境或自定义工具在编译时或运行时读取和处理。 自定义属性的概念源于C#和.NET Framework,但也可...
本文将深入探讨如何使用C#语言来创建自定义特性,并通过反射来获取这些特性的元数据值。这是一项关键技能,特别是在设计灵活、可扩展的框架或者需要在运行时动态调整行为的应用程序时。 首先,让我们了解什么是特性...
自定义描述符提供者是.NET框架中用于扩展元数据系统的关键机制,它允许开发者自定义类型、属性、事件等的元数据行为。在C#组件开发中,理解并熟练运用这一技术可以极大地提升代码的灵活性和可扩展性。 首先,我们...