7

現在、Lambdasと連携して非常に優れた処理を実行するFluent実装がたくさんあります。脳を包み込んで、こういうものを作り始めたいのですが、脳が理解できる説明がまだ見つかりません。

PersonValidatorのこの簡単な例を考えてみましょう

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を拡張する拡張メソッドを作成できます。

ですから、前半と後半は問題があるようですが、どうやってまとめたらいいのかわかりません。

意味のある説明を探しています...「入手」したいのですが。:)

4

2 に答える 2

5

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

正確な実装はもう少し複雑にする必要があると思います。以下の例で洞察が得られることを願っています。同じ一般的なルールですが、流暢なインターフェイスを作成するには「this」を返します。

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

上記は流暢なインターフェースを作成する方法を示していますが、この特定の状況で長期的に何を購入できるかはわかりません。具体的なバリデーターの内部でのみ使用されているように見える流暢なインターフェースの利便性のために、バリデーターのコンシューマーに有用で流暢なインターフェースを実際に提供することなく、コードの複雑さをかなり増やしました。具体的なバリデーターを作成するための流暢なフレームワークを提供するのではなく、検証を実行する必要のある開発者に流暢な検証フレームワークを提供することで、より多くの価値を集めることができると思います。

于 2009-08-21T03:58:31.263 に答える
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));
于 2009-08-21T04:09:07.263 に答える