2009-08-21 13 views
7

Lambdaには非常にきれいなことをするためのFluentの実装がたくさんあります。私はそれらの周りに私の脳をラップしたいので、これらのもののいくつかを作成することができますが、私はまだ私の脳が理解する説明を見つける必要があります。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

あなたの例では、意味がありません、あなたが追加ルール()。CannotBeNull()。CannotBeBlank()あなたがあなたのバリデーションルールにそれらのルールを追加して後で適用したいと言っていますか? –

+0

はい、正確です。私はAddRuleを使用して、クラスの与えられたプロパティに対してバリデーションを適用する任意の数の連鎖したメソッドを使用できるようにしたいと考えています。 私の挑戦は、私が "AddRule"の中で何をすべきかわからないということです。私はバリデーターにそれらを残す必要があることを知っていますが、私はそれを行う方法を知らないのですか? – ctorx

答えて

5

流暢なインターフェイスの鍵は、CannotBeNull()やCannotBeBlank()などのメソッドが現在のインスタンス(つまりthis)を返すことです。 ValidationResultを返す代わりにAddRuleメソッドを "流暢"にするには、IValidatorの現在のインスタンスを返す必要があります。拡張メソッドは、拡張しているIValidatorのインスタンスも返す必要があります。

私はあなたの正確な実装はもう少し複雑にする必要があるかもしれないと思っています。以下の例は、いくつかの洞察を提供します。上記の流れるようなインターフェイスを作成する方法を示しますが

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; 
    } 
} 

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; 
    } 
} 

上記のようにのように使用することができます。同じ原則、しかし...戻る「この」流れるようなインターフェイスを作成します私はこの特定の状況で長期的にあなたが購入するものを本当に知っていません。コンクリートバリデータの内部でのみ使用されるように見える流暢なインターフェイスの便利さのために、バリデータのコンシューマに実用的で流暢なインターフェイスを提供することなく、コードの複雑さをかなり増やしました。具体的なバリデータを作成するための流暢なフレームワークを提供するのではなく、検証を実行する必要がある開発者に流暢な検証フレームワークを提供することで、より多くの価値を掴むことができます。

+0

+1それは私が書くつもりでしたが、あなたは私にそれを打ち負かしました。だから私は別のアプローチを取った。 –

+0

ここで重要なのは、「ルール」で何が起こるかです。ローカルリストはどのように見え、どのように利用されていますか? – ctorx

+0

最も簡単な解決策は、ルールをローカルリスト>にすることです。AddRuleメソッドはIValidatorRuleを作成してそのコレクションに追加する必要があり、拡張メソッドを使用して流暢なインターフェイスを介してそのインスタンスを変更することができます。それ以外は、私はあなたの努力が非常に少ない利益のために費やしていると思います。あなたが流暢なインターフェースの利点を本当に実現したいのであれば、私はあなたの検証フレームワークを考え直すでしょう。具体的なバリデータ(PersonValidator)を提供するのではなく、バリデーションを行う人のために流暢なインターフェースを提供してください。 – jrista

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

+1

それは違うアプローチなので、他の誰かが私の前で答えたので、私はちょうどそれを忘れるのではなく、私のコードを終わらせたいと思った。 –

関連する問題