验证能有多优雅
背景
我們都知道ENTLIB有VAB,也知道如果不在乎大量的XML損視力的話,VAB非常非常優(yōu)雅,但是在不大的項目中,很多情況下我們依舊自己寫著驗證的代碼
所以在這篇文章中,打算展示一下學習.NET一年半以來,寫驗證代碼的各個階段,并展示一種個人覺得比較優(yōu)雅的驗證代碼的寫法,如果大家有別的方案,也請?zhí)岢鰜砼c大家分享哦
?
第一階段--強寫
所謂強寫,自然就是強行地寫了,從知道需要參數(shù)驗證(很慚愧,學了.NET整整1個月才知道這事)開始,好長一段時間都在強寫著驗證的代碼,也不記得什么時候開始覺得這么寫不舒服,什么時候開始換成了別的方法,總之早期的代碼中充斥著這樣的片斷
public?void?SomeMethod(string?s){
????if?(s?==?null)
????{
????????throw?new?ArgumentNullException("s");
????}
????if?(s.Length?==?0)
????{
????????throw?new?ArgumentException("s?cannot?be?empty?");
????}
}
最終的結(jié)果是,一個.cs文件中有整整1/2的內(nèi)容是這些可愛的if, throw和花括號
這個方案不用評價了,我自己會把他貶得很慘,再怎么說曾經(jīng)也是為了這些東西寫到手抽筋啊,痛苦啊
?
?
第二階段--Guard類
?
嗯,MS很多項目中都有這個Guard類,把一些主要的驗證的方法寫在了類中,方法直接拋出異常,大致是這樣的
public?class?Guard{
????public?void?NotNull(object?value,?string?argName)
????{
????????if?(value?==?null)
????????{
????????????throw?new?ArgumentNullException(argName);
????????}
????}
????//其他驗證方法
}
?
調(diào)用的方法大致是這樣的
public?void?SomeMethod(string?s){
????Guard.NotNull(s,?"s");
????Guard.NotEmpty(s,?"s");
????Guard.ShorterThan(s,?10,?"s");
????Guard.LongerThan(s,?3,?"s");
????//其他邏輯
}
看起來清爽多了,再也沒有if, throw和美麗的花括號了,可喜可賀~可喜可賀~
?
但是!并不是一切都這么美好的!每一次調(diào)用方法都需要值一個字符串以表示參數(shù)的名稱,這里寫了4個”s”,當然你會說4個”s”沒什么,但是寫4個”user.Name”再寫6個”user.CreationDate”呢……
什么感覺?手酸?NO~NO~這不是最重要的,重要的是寫字符串的時候VS沒有自動提示啊!你敢保證寫10個不錯一個字母么?
其實對這個階段還是非常有感情的,怎么說都是對“把類似功能合在一起”的理念的嘗試呢
?
第三階段--擴展方法
然后,然后就有了C# 3.0,就有了擴展方法,然后Guard中的方法的第一個參數(shù)都加了一個this,調(diào)用就成了這樣
public?void?SomeMethod(string?s){
????s.NotNull("s");
????s.NotEmpty("s");
????s.ShorterThan(10,?"s");
????s.LongerThan(3,?"s");
????//其他邏輯
}
基本我不認可這是一個階段呢,只是用了點語法糖而已,最重要的字符串多次輸入?yún)?shù)名稱的問題根本沒有得到解決,少打幾個字會很快樂么……作為一個標準的程序員,我想說:NO!
?
?
第四階段--不知道怎么說
?
就是現(xiàn)在在用的方法啦,剛剛“發(fā)明”出來的哦,個人自我感覺良好,但實在不知道怎么從設(shè)計上去解釋,就先寫一下實現(xiàn)方案吧
很久很久以前,有一個孤獨的類,句叫ValidationHelper<T>,他的任務(wù)就是懲治世上所有不聽話的參數(shù),根據(jù)見過他的變量們的描述,他是長得這樣的
?
Codepublic class ValidationHelper<T>
{
#region 成員
private T m_Value;
private string m_Name;
#endregion
#region 屬性
/// <summary>
/// 獲取待驗證的參數(shù)的值.
/// </summary>
public T Value
{
get
{
return m_Value;
}
}
/// <summary>
/// 獲取待驗證的參數(shù)的名稱.
/// </summary>
public string Name
{
get
{
return m_Name;
}
}
#endregion
#region 構(gòu)造函數(shù)
/// <summary>
/// 創(chuàng)建一個<see cref="ValidationHelper<T>"/>的對象.
/// </summary>
/// <param name="value">待驗證的參數(shù)的值.</param>
/// <param name="name">待驗證的參數(shù)的名稱.</param>
public ValidationHelper(T value, string name)
{
m_Value = value;
m_Name = name;
}
#endregion
#region 基本方法
/// <summary>
/// 驗證參數(shù)不為其默認值.
/// </summary>
/// <returns>this指針以方便鏈式調(diào)用.</returns>
/// <exception cref="ArgumentException">參數(shù)為值類型且為默認值.</exception>
/// <exception cref="ArgumentNullException">參數(shù)為引用類型且為null.</exception>
public ValidationHelper<T> NotDefault()
{
if (Value.Equals(default(T)))
{
if (Value is ValueType)
{
throw new ArgumentException(
String.Format("參數(shù){0}不能使用默認值", Name), Name);
}
else
{
throw new ArgumentNullException(
String.Format("參數(shù){0}不能為null", Name), Name);
}
}
return this;
}
/// <summary>
/// 使用自定義方法進行驗證.
/// </summary>
/// <param name="rule">用以驗證的自定義方法.</param>
/// <returns>this指針以方便鏈式調(diào)用.</returns>
/// <exception cref="Exception">驗證失敗拋出相應(yīng)異常.</exception>
/// <remarks><paramref name="rule"/>的第一個參數(shù)為參數(shù)值,第二個參數(shù)為參數(shù)名稱.</remarks>
public ValidationHelper<T> CustomRule(Action<T, string> rule)
{
rule(Value, Name);
return this;
}
#endregion
}
?
?
因為ValidationHelper<T>可以保存住參數(shù)的值和參數(shù)的名稱,因此就一下子地解決了多次輸入?yún)?shù)名稱的問題,真不虧是大俠啊
但是,很多人都不知道,為什么功能這么少的ValidationHelper<T>可以消滅幾乎所有的不規(guī)范參數(shù),其實秘訣還在于擴展方法,通過擴展方法的聯(lián)系,ValidationHelper<T>找到了很多伙伴,其實除暴安良的,是一個團隊,而非一個人,下面來看看StringValidationHelper是怎么樣對付不規(guī)范的string的吧
Code
public static class StringValidationHelper
{
/// <summary>
/// 驗證<see cref="System.String"/>類型的參數(shù)不為空.
/// </summary>
/// <param name="current">用于驗證的<see cref="ValidationHelper<T>"/></param>
/// <returns><paramref name="current"/>的引用以方便鏈式調(diào)用.</returns>
public static ValidationHelper<string> NotEmpty(this ValidationHelper<string> current)
{
current.NotDefault();
if (current.Value.Length == 0)
{
throw new ArgumentException(
String.Format("{0}不可為空字符串", current.Name), current.Name);
}
return current;
}
/// <summary>
/// 驗證<see cref="System.String"/>類型的參數(shù)的長度小于一定值.
/// </summary>
/// <param name="current">用于驗證的<see cref="ValidationHelper<T>"/></param>
/// <param name="length">可行的最大長度(包括此值).</param>
/// <returns><paramref name="current"/>的引用以方便鏈式調(diào)用.</returns>
public static ValidationHelper<string> ShorterThan(this ValidationHelper<string> current, int length)
{
current.NotDefault();
if (current.Value.Length > length)
{
throw new ArgumentException(
String.Format("{0}的長度不可超過{1}", current.Name, length), current.Name);
}
return current;
}
/// <summary>
/// 驗證<see cref="System.String"/>類型的參數(shù)的長度大于一定值.
/// </summary>
/// <param name="current">用于驗證的<see cref="ValidationHelper<T>"/></param>
/// <param name="length">可行的最小長度(包括此值).</param>
/// <returns><paramref name="current"/>的引用以方便鏈式調(diào)用.</returns>
public static ValidationHelper<string> LongerThan(this ValidationHelper<string> current, int length)
{
current.NotDefault();
if (current.Value.Length < length)
{
throw new ArgumentException(
String.Format("{0}的長度不可小于{1}", current.Name, length), current.Name);
}
return current;
}
/// <summary>
/// 驗證<see cref="System.String"/>類型的參數(shù)的長度在一定值之間.
/// </summary>
/// <param name="current">用于驗證的<see cref="ValidationHelper<T>"/></param>
/// <param name="minLength">可行的最小長度(包括此值).</param>
/// <param name="maxLength">可行的最大長度(包括此值).</param>
/// <returns><paramref name="current"/>的引用以方便鏈式調(diào)用.</returns>
public static ValidationHelper<string> LengthBetween(this ValidationHelper<string> current, int minLength, int maxLength)
{
current.NotDefault();
if (current.Value.Length < minLength || current.Value.Length > maxLength)
{
throw new ArgumentException(
String.Format("{0}的長度必須在{1}和{2}之間", current.Name, minLength, maxLength), current.Name);
}
return current;
}
}
好了,伙伴找到了,現(xiàn)在的問題是,當需要大俠幫助的時候,我們不得不使出全身的力氣使用new來召喚大俠……這顯然很不爽,因此又有了一擴展方法,我們稱之為“工廠”
public?static?class?Validation{
????public?static?ValidationHelper<T>?InitValidation<T>(this?T?value,?string?argName)
????{
????????return?new?ValidationHelper<T>(value,?argName);
????}
}
最后,我們是這樣來打敗黑暗勢力的
public?void?SomeMethod(string?s){
????s.InitValidation("s")
????????.NotDefault()
????????.NotEmpty()
????????.ShorterThan(10)
????????.LongerThan(3);
}
反正本人是找不到更好的方法了,還請大家指教了
轉(zhuǎn)載于:https://www.cnblogs.com/GrayZhang/archive/2008/09/01/1281526.html
總結(jié)
- 上一篇: jsp页面中使用超链接标签a中的属性hr
- 下一篇: Unity_UIWidgets学习笔记0