2009-08-21 45 views
7

現在有許多Fluent實現與Lambdas一起完成非常整齊的工作。我想圍繞它把自己的大腦包裹起來,這樣我就可以開始創造這些東西了,但是我還沒有找到我的大腦理解的解釋。Lambda Func <>和Fluent

考量一個人驗證

public class PersonValidator : IValidator<Person> 
{ 
    public PersonValidator() 
    { 
      AddRule(p => p.FirstName).CannotBeNull().CannotBeBlank(); 
      AddRule(p => p.LastName).CannotBeNull().CannotBeBlank(); 
    } 

    public List<ValidationResult> Validate(Person p) 
    { 
     // pseudo... 
     apply all rules specified in constructor, return results 
    } 
} 

我設法讓這一切使用方法上我的驗證這樣的工作的一部分...

public ValidationResult<T,TProp> AddRule<T,TProp>(Func<T,TProp> property) 
{ 
    ... not sure what to do here. This method gives me the ability to use the lambda 
    ... for specifying which properties i want to validate 
} 

我的這個簡單的例子然後可以創建用於CannotBeNull和CannotBeEmpty的擴展IValidator的擴展方法。

所以看起來我有上半年和下半年的問題,但我不知道如何把它們放在一起。

尋找一個有意義的解釋...我想「得到它」。 :)

+0

你的例子是沒有意義的,當你做AddRule()。CannotBeNull()。CannotBeBlank()你說你想要這些規則添加到您的驗證規則,後來申請呢? – 2009-08-21 03:48:48

+0

是的,確切地說。我希望能夠使用AddRule,然後使用任何數量的鏈接方法對類的給定屬性應用驗證。 我的挑戰是我不知道在「AddRule」裏面做什麼。我知道我需要堅持那些驗證者,但我不知道該怎麼做? – ctorx 2009-08-21 15:18:42

回答

5

流暢接口的關鍵是CannotBeNull()和CannotBeBlank()方法返回當前實例(即this)。如果你想讓你的AddRule方法「流利」,而不是返回ValidationResult,你需要返回當前的IValidator實例。您的擴展方法還需要返回它們正在擴展的IValidator的實例。

我認爲你的確切實現可能需要更復雜一點,希望下面的例子能夠提供一些見解。同一般的規則,但是......返回「這」創造了流暢的界面:

interface IValidator<T> 
{ 
    IValidatorRule<T, TProp> AddRule<TProp>(Func<T, TProp> property); 
} 

interface IValidatorRule<T> 
{ 
    T instance { get; } 
    string PropertyName { get; } 

    ValidationResult Apply(T instance); 
} 

public static IValidatorAugmentorExtensions 
{ 
    public static IValidatorRule<T> CannotBeNull(this IValidatorRule<T> rule) 
    { 
     // ... 

     return rule; 
    } 

    public static IValidatorRule<T> CannotBeBlank(this IValidatorRule<T> rule) 
    { 
     // ... 

     return rule; 
    } 
} 

以上可以使用像這樣:

public class PersonValidator: IValidator<Person> 
{ 
    public PersonValidator() 
    { 
     AddRule(p => p.FirstName).CannotBeNull().CannotBeEmpty(); 
     AddRule(p => p.LastName).CannotBeNull().CannotBeEmpty(); 
    }  

    public List<ValidationResult> Validate(Person p) 
    { 
     List<ValidationResult> results = new List<ValidationResult>(); 

     foreach (IValidatorRule<Person> rule in rules) // don't know where rules is, or what the AddRule method adds to...you'll need to figure that out 
     { 
      results = rule.Apply(p); 
     } 

     return results; 
    } 
} 

雖然上面演示如何創建一個流暢的界面,在這種特殊情況下,我並不真正瞭解它從長遠來看會給你帶來什麼。爲了方便流暢的界面,似乎只在內部使用具體的驗證器,您已經將代碼的複雜性提高了相當多,而沒有真正爲驗證器的用戶提供有用的流暢接口。我認爲,通過爲需要執行驗證的開發人員提供流暢的驗證框架,而不是提供流暢的框架來創建具體的驗證器,您會收穫更多價值。

+0

+1這就是我要寫的東西,但是你打敗了我。所以我採取了不同的方法。 – 2009-08-21 04:11:51

+0

他們的關鍵需要在這裏,「規則」會發生什麼。本地列表是什麼樣的,它是如何使用的? – ctorx 2009-08-21 14:59:54

+0

最簡單的解決方案是使規則成爲本地列表>。AddRule方法應創建IValidatorRule並將其添加到該集合,並使用擴展方法通過流暢接口修改該實例。除此之外,我需要再次強調的是,我認爲你花費很少的努力花費很多。如果你真的想要體會流暢接口的好處,我會重新考慮你的驗證框架。而不是提供具體的驗證器(即PersonValidator),爲那些進行驗證的人提供流暢的接口。 – jrista 2009-08-21 20:26:05

1

jrista的回答是正確的。只是爲了在這裏採用不同的方法,我是如何完成它的。

public class PersonValidator : IValidator<Person> 
    { 
     List<Func<Person,bool>> validationRules = new List<Func<Person,bool>>(); 

    public PersonValidator() 
    { 
     AddRule(p => IsNullOrEmpty(p.FirstName)).AddRule(p1 => CheckLength(p1.FirstName)); 
    } 

    PersonValidator AddRule(Func<Person,bool> rule) 
    { 
     this.validationRules.Add(rule); 
     return this; 
    } 

    private bool IsNullOrEmpty(String stringToCheck) 
    { 
     return String.IsNullOrEmpty(stringToCheck); 
    } 

    private bool CheckLength(String stringToCheck) 
    { 
     return (String.IsNullOrEmpty(stringToCheck) ? false : stringToCheck.Length < 3); 
    } 

    #region IValidator<Person> Members 

    public bool Validate(Person obj) 
    { 
     return validationRules.Select(x => x(obj)).All(result => result == false); 
    } 

    #endregion 
} 



     Person test = new Person() { FirstName = null }; 
     Person test1 = new Person() { FirstName = "St" }; 
     Person valid = new Person() { FirstName = "John" }; 

     PersonValidator validator = new PersonValidator(); 
     Console.WriteLine("{0} {1} {2}", validator.Validate(test), validator.Validate(test1), validator.Validate(valid)); 
+0

我不明白這個例子會如何促進這種用法... AddRule(x => x.FirstName).IsNullOrEmpty(); – ctorx 2009-08-21 14:53:58

+1

它不會因爲它不同的方法,我只想完成我的代碼,而不是僅僅因爲別人在我之前回答而忘記它。 – 2009-08-21 15:19:06

相關問題