2009-08-21 44 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

相关问题