本系列主旨是记录本人在项目开发和语言的学习中总结的小技巧,自知能力有限,不足登大雅之堂,但本着学习和交流的态度,希望各位同仁给与批评和指正。
在此不胜感激!!
转载请注明出处:http://suchenge.cnblogs.com
前文摘要:
我在2010年4月8日发表了一篇文章:《开发笔记——通过反射验证对象属性》
感谢大家对那片文章的关注和指导,在文章的回复中Artech和henry的指导使我受益匪浅,我根据这两位博友的指导意见重新编写了代码,同时也参考了《Smark.Data实体成员数据验证》这篇文章的代码思路,现在将设计思路和工程代码发布在此篇博文中,也算是回馈各位博友对我的支持和关注,同时也算是对Artech和henry的指导交的作业。
依据Artech和henry的指导和《Smark.Data实体成员数据验证》这篇文章的代码思路,我将验证修饰和验证过程设计为以下方式:
一、验证修饰对象的定义
/// 验证属性抽象对象
/// </summary>
[AttributeUsage(AttributeTargets.Property, Inherited = false , AllowMultiple = true )]
public abstract class ValidatorAttribute : Attribute
{
/// <summary>
/// 说明
/// </summary>
protected string m_Message;
public void Validating < T > ( object value, T sender) where T : BaseObject
{
if ( ! OnValidating(value))
{
ErrorMessage errorMessage = new ErrorMessage(m_Message, "" );
sender.Errors.Add(errorMessage);
}
}
protected abstract bool OnValidating( object value);
protected virtual bool RegexTest( object value, string regex)
{
bool result = false ;
string data = value.ToString();
if (data != null && ! string .IsNullOrEmpty(data))
{
result = Regex.IsMatch(value.ToString(), regex);
}
return result;
}
}
/// <summary>
/// 不允许为空值的验证属性
/// </summary>
public class NotNULL : ValidatorAttribute
{
public NotNULL( string message)
{
m_Message = message;
}
protected override bool OnValidating( object value)
{
return value != null && ! string .IsNullOrEmpty(value.ToString());
}
}
/// <summary>
/// String类型的长度验证
/// </summary>
public class StringLength : ValidatorAttribute
{
private int m_MaxLength;
private int m_MinLength;
public StringLength( string message, int minLength, int maxLength)
{
m_Message = message;
m_MaxLength = maxLength;
m_MinLength = minLength;
}
protected override bool OnValidating( object value)
{
bool result = false ;
string data = value.ToString();
if ( ! string .IsNullOrEmpty(value.ToString()))
{
if (data.Length >= m_MinLength && data.Length <= m_MaxLength)
{
result = true ;
}
}
return result;
}
}
/// <summary>
/// 数值类型的验证
/// </summary>
public class Number : ValidatorAttribute
{
private int m_MinValue;
private int m_MaxValue;
public Number( string message, int minValue, int maxValue)
{
m_Message = message;
m_MaxValue = maxValue;
m_MinValue = minValue;
}
protected override bool OnValidating( object value)
{
bool result = false ;
string data = value.ToString();
if ( ! string .IsNullOrEmpty(data))
{
if (RegexTest(data, @" \d+ " ))
{
int tmp = int .Parse(data);
if (m_MinValue != 0 )
{
if (tmp >= m_MinValue)
{
result = true ;
}
}
if (m_MaxValue != 0 )
{
if (tmp <= m_MaxValue)
{
result = true ;
}
}
}
}
return result;
}
}
/// <summary>
/// 通过正则表达式方式验证
/// </summary>
public class Match: ValidatorAttribute
{
private string m_Regex = string .Empty;
public Match( string message, string regex)
{
m_Message = message;
m_Regex = regex;
}
protected override bool OnValidating( object value)
{
bool result = false ;
string data = value.ToString();
if ( ! string .IsNullOrEmpty(data))
{
return RegexTest(value, m_Regex);
}
return result;
}
}
验证修饰对象的定义,我简单的定义了对于String类型和Number类型值的验证修饰和通过正则表达式验证的验证修饰,根据《Smark.Data实体成员数据验证》,我们还可以定义通过数据库或其他方式验证数据有效性的修饰对象,比如验证一个对象的属性是否存在于数据库中等。
二、验证过程的定义
{
public static void Scan < T > (T baseObject) where T : BaseObject
{
Type type = baseObject.GetType();
foreach (PropertyInfo P in type.GetProperties())
{
object pv = P.GetValue(baseObject, null );
foreach (ValidatorAttribute attr in P.GetCustomAttributes( true ))
{
attr.Validating(pv,baseObject);
}
}
}
}
验证过程函数中使用了泛型并约束月BaseObject对象的思路是,通过Scan验证的对象都继承与BaseObject对象,而BaseObject对象中含有错误消息集合ErrorMessageCollection,这样就可以将对属性验证的错误信息记录在对象的ErrorMessageCollection集合中,方便显示和处理。
三、错误消息的记录
我在这里设计了错误消息的记录方式,是通过Items<T>集合对象,ErrorMessage对象和ErrorMessageCollection对象来实现的,设计之初的思路是想给某一对象在实际使用中出现的错误找到一个放置的地方,并且这些错误消息是附属在对象上的,实现之后,反思觉得这样的设计有些耦合太紧了。
/// 系统自定义集合对象,实现了IEnumerable接口
/// </summary>
/// <typeparam name="T"> 用存于集合的对象的类型名称 </typeparam>
public class Items < T > : IEnumerable
{
/// <summary>
/// 集合容器List <> 类型
/// </summary>
protected List < T > arr = new List < T > ();
/// <summary>
/// 必须实现的迭代器
/// </summary>
/// <returns></returns>
public IEnumerator GetEnumerator()
{
foreach (T t in arr)
{
yield return t;
}
}
/// <summary>
/// 获取集合中的第一个对象,如果未找到返回对象默认
/// </summary>
public virtual T First
{
get
{
if (arr.Count > 0 )
return arr[ 0 ];
else
return default (T);
}
}
/// <summary>
/// 获取集合中的最后一个对象,如果未找到返回对象默认
/// </summary>
public virtual T Last
{
get
{
if (Count > 0 )
return arr[arr.Count - 1 ];
else
return default (T);
}
}
/// <summary>
/// 添加对象到集合
/// </summary>
public virtual void Add(T t)
{
arr.Add(t);
}
public virtual void AddList(Items < T > ts)
{
foreach (T t in ts)
{
arr.Add(t);
}
}
/// <summary>
/// 添加对象到集合,是否可重复添加
/// </summary>
/// <param name="t"> 要添加的对象 </param>
/// <param name="skipcontain"> 是否跳过包含;true:无论现有集合是否还有要添加的对象,都将要添加的对象添加到集合中;false:如果现有集合中含有要添加的对象,则不添加此对象 </param>
public virtual void Add(T t, bool skipcontain)
{
if (skipcontain)
Add(t);
else
{
if ( ! Contains(t))
Add(t);
}
}
/// <summary>
/// 返回集合中对象的数量
/// </summary>
public virtual int Count
{
get { return arr.Count; }
}
/// <summary>
/// 返回指定参数Index为索引的对象
/// </summary>
public virtual T this [ int Index]
{
get
{
if (Index < arr.Count)
return arr[Index];
else
return default (T);
}
}
/// <summary>
/// 获取集合中是否存在对象的布尔值
/// </summary>
public virtual bool HasItem
{
get
{
bool b = false ;
if (arr.Count > 0 )
b = true ;
return b;
}
}
/// <summary>
/// 清空集合
/// </summary>
public virtual void Clear()
{
arr.Clear();
arr.RemoveRange( 0 , arr.Count);
}
/// <summary>
/// 是否包含某项
/// </summary>
/// <param name="t"> 要检测的对象 </param>
/// <returns> 是否包含 </returns>
public virtual bool Contains(T t)
{
return arr.Contains(t);
}
/// <summary>
/// 删除指定索引的集合元素
/// </summary>
/// <param name="index"></param>
public virtual void Remove( int index)
{
if (index > - 1 && index < Count)
{
arr.RemoveAt(index);
}
}
public virtual void Remove(T t)
{
arr.Remove(t);
}
public virtual void RemoveAll(T t)
{
foreach (T tmp in arr)
{
if (tmp.Equals(t))
arr.Remove(t);
}
}
}
/// 错误消息处理委托
/// </summary>
/// <param name="message"> 自定义错误消息 </param>
/// <param name="systemmessage"> 系统错误消息 </param>
public delegate void ErrorHandle( string message, string systemmessage);
/// <summary>
/// 错误消息类
/// </summary>
public class ErrorMessage
{
/// <summary>
/// 自定义错误消息
/// </summary>
private string _message = "" ;
/// <summary>
/// 系统错误消息
/// </summary>
private string _systemmessage = "" ;
/// <summary>
/// 获取或设置自定义错误消息
/// </summary>
public string Message
{
get { return _message; }
set { _message = value; }
}
/// <summary>
/// 获取或设置系统错误消息
/// </summary>
public string SystemMessage
{
get { return _systemmessage; }
set { _systemmessage = value; }
}
public ErrorMessage()
{ }
/// <summary>
///
/// </summary>
/// <param name="message"> 自定义错误消息 </param>
/// <param name="systemmessage"> 系统错误消息 </param>
public ErrorMessage( string message, string systemmessage)
{
_message = message;
_systemmessage = systemmessage;
}
/// <summary>
/// 返回自定义错误消息
/// </summary>
/// <returns> 自定义错误消息 </returns>
public override string ToString()
{
return _message;
}
/// <summary>
/// 通过参数t,返回错误消息
/// </summary>
/// <param name="t"> 返回错误类型,m:自定义错误;s:系统错误 </param>
/// <returns></returns>
public string ToString( string t)
{
string tmp = "" ;
if (t == " m " )
tmp = _message;
if (t == " s " )
tmp = _systemmessage;
return tmp;
}
/// <summary>
/// 消息错误的类型枚举:Message,SystemMessage
/// </summary>
public enum Type
{
Message,
SystemMessage
}
public bool Equals(ErrorMessage obj)
{
bool retult = false ;
if ((_message == obj.Message) && _systemmessage == obj._systemmessage)
retult = true ;
return retult;
}
}
/// <summary>
/// 自定义错误类型
/// </summary>
public enum ErrorMessageType
{
Message,
SystemMessage
}
{
private const string _Separator = " -_- " ;
/// <summary>
/// 获取本类下定义的默认分隔符
/// </summary>
public string Separator
{
get { return _Separator; }
}
/// <summary>
/// 实例化错误消息集合
/// </summary>
public ErrorMessageCollection()
{}
/// <summary>
/// 实例化错误消息集合,将error参数以separator参数为分割后,添加到实例集合中
/// </summary>
/// <param name="error"> 错误消息字符串 </param>
/// <param name="separator"> 分隔符 </param>
public ErrorMessageCollection( string error, char [] separator)
{
string [] err = error.Split(separator, StringSplitOptions.RemoveEmptyEntries);
foreach ( string e in err) Add(e);
}
/// <summary>
/// 添加只包含自定义错误消息的错误消息
/// </summary>
/// <param name="message"> 自定义错误消息 </param>
public void Add( string message)
{
ErrorMessage objEm = new ErrorMessage(message, "" );
Add(objEm);
}
/// <summary>
/// 添加只包含自定义错误消息的错误消息
/// </summary>
/// <param name="message"> 自定义错误消息 </param>
/// <param name="eh"> 外部事件 </param>
public void Add( string message, ErrorHandle eh) {
ErrorMessage objEm = new ErrorMessage(message, "" );
Add(objEm);
eh(message, "" );
}
/// <summary>
/// 添加错误消息
/// </summary>
/// <param name="message"> 自定义错误消息 </param>
/// <param name="systemmessage"> 系统错误消息 </param>
public void Add( string message, string systemmessage)
{
ErrorMessage objEm = new ErrorMessage(message, systemmessage);
Add(objEm);
}
/// <summary>
/// 添加错误消息
/// </summary>
/// <param name="message"> 自定义错误消息 </param>
/// <param name="systemmessage"> 系统错误消息 </param>
/// <param name="eh"> 外部事件 </param>
public void Add( string message, string systemmessage, ErrorHandle eh)
{
ErrorMessage objEm = new ErrorMessage(message, systemmessage);
Add(objEm);
eh(message, systemmessage);
}
/// <summary>
/// 是否存在错误消息
/// </summary>
public override bool HasItem {
get {
if (Count > 0 ) return true ;
else return false ;
}
}
/// <summary>
/// 获取集合中第一个错误消息对象,如果未找到返回错误消息对象(ErrorMessage)默认值
/// </summary>
public override ErrorMessage First
{
get
{
if (HasItem)
return this [ 0 ];
else
return default (ErrorMessage);
}
}
/// <summary>
/// 获取集合中最后一个错误消息对象,如果未找到返回错误消息对象(ErrorMessage)默认值
/// </summary>
public new ErrorMessage Last
{
get
{
if (HasItem)
return this [Count - 1 ];
else
return default (ErrorMessage);
}
}
/// <summary>
/// 重写的索引器,根据参数index返回集合中的指定错误消息对象
/// </summary>
/// <param name="index"> 索引位置 </param>
/// <returns> ErrorMessage错误消息对象 </returns>
public override ErrorMessage this [ int index]
{
get
{
if (Count > 0 && index <= (Count - 1 ))
return arr[index];
else
return null ;
}
}
/// <summary>
/// 重写的方法,返回集合中所有的错误消息对象中的自定义错误消息,并以系统默认分隔符组成字符串
/// </summary>
/// <returns> 集合中所有的错误消息对象中的自定义错误消息,并以系统默认分隔符组成字符串 </returns>
public override string ToString()
{
return ToString(ErrorMessageType.Message);
}
/// <summary>
/// 重写的方法,返回集合中所有的错误消息对象中的自定义错误消息,并以系统默认分隔符组成字符串
/// </summary>
/// <param name="errorMessageType"> 自定义错误消息的字段类型 </param>
/// <returns> 集合中所有的错误消息对象中的自定义错误消息,并以系统默认分隔符组成字符串 </returns>
public string ToString(ErrorMessageType errorMessageType)
{
string result = string .Empty;
if (Count > 0 )
{
StringBuilder stringBuilder = new StringBuilder();
foreach (ErrorMessage errorMessage in arr)
{
stringBuilder.AppendFormat( " {0}{1} " ,
errorMessageType == ErrorMessageType.Message
? errorMessage.Message
: errorMessage.SystemMessage,
_Separator);
}
result = stringBuilder.ToString();
}
return result;
}
public string ToString( string replaceSeparator)
{
return ToString().Replace(_Separator, replaceSeparator);
}
public string ToString(ErrorMessageType errorMessageType, string replaceSeparator)
{
return ToString(errorMessageType).Replace(_Separator, replaceSeparator);
}
/// <summary>
/// 添加系统错误消息
/// </summary>
/// <param name="err"> 系统消息集合 </param>
public void Add(ErrorMessageCollection err)
{
foreach (ErrorMessage em in err) Add(em);
}
public override void Remove(ErrorMessage t)
{
for ( int i = 0 ; i < Count; i ++ )
{
if ( this [i].Equals(t)) Remove(i);
break ;
}
}
}
{
protected ErrorMessageCollection m_Errors;
public ErrorMessageCollection Errors
{
get { return m_Errors; }
set { m_Errors = value; }
}
public BaseObject()
{
m_Errors = new ErrorMessageCollection();
}
}
四、对象验证修饰的定义和验证过程
1、给对象属性加上验证修饰
{
private string m_Name;
private string m_Age;
private string m_Email;
[NotNULL( " 用户名不能为空 " )]
[StringLength( " 用户名长度在4-16位 " , 4 , 16 )]
public string Name
{
get { return m_Name; }
set { m_Name = value; }
}
[Number( " 用户年龄在18以及18岁以上 " , 18 , 0 )]
public string Age
{
get { return m_Age; }
set { m_Age = value; }
}
[Match( " Email地址必须填写正确 " , @" ^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$ " )]
public string Email
{
get { return m_Email; }
set { m_Email = value; }
}
public ObjectModel()
{ }
}
2、验证过程
{
ObjectModel objectModel = new ObjectModel();
objectModel.Name = textBox1.Text;
objectModel.Age = textBox2.Text;
objectModel.Email = textBox3.Text;
Validator.Scan(objectModel);//调用验证过程
if (objectModel.Errors.HasItem)
{
MessageBox.Show(objectModel.Errors.ToString( " \n " ));
}
else
{
MessageBox.Show( " 验证成功!! " );
}
}
}
代码下载:ExampleProject.rar