7

エンティティ型オブジェクトのプロパティを検証する ValidationRule クラスを作成しようとしています。検査するプロパティの名前を設定してから、オブジェクトが IsValid() メソッドを実行するときに実行時に評価されるデリゲートまたはラムダ式をクラスに与えたいと思います。このようなもののスニペット、または匿名メソッドを引数またはプロパティとして渡す方法に関するアイデアはありますか?

また、私が達成しようとしていることを説明しているかどうかわからないので、明確でない場合は質問してください。

4

5 に答える 5

6

実際に使用したいのはFunc<T,bool>、T が検証したいアイテムのタイプである場所です。次に、このようなことをします

validator.AddValidation(item => (item.HasEnoughInformation() || item.IsEmpty());

に保存できますList<Func<T,bool>>

于 2008-09-26T21:35:39.960 に答える
3
class ValidationRule {
    public delegate bool Validator();

    private Validator _v;

    public ValidationRule(Validator v) { _v = v; }

    public Validator Validator {
        get { return _v; }
        set { _v = value; }
    }

    public bool IsValid { get { return _v(); } }
}

var alwaysPasses = new ValidationRule(() => true);
var alwaysFails = new ValidationRule(() => false);

var textBoxHasText = new ValidationRule(() => textBox1.Text.Length > 0);

これで始められるはずです。しかし、実際には、ここでは継承の方がはるかに適切です。問題は、Validatorが閉じない状態にアクセスできないことです。これはValidationRules、独自の状態を含むと言うほど再利用できないことを意味します。次のクラスを前の の定義と比較してくださいtextBoxHasText

interface IValidationRule {
    bool IsValid { get; }
}

class BoxHasText : IValidationRule {
    TextBox _c;

    public BoxHasText(TextBox c) { _c = c; }

    public bool IsValid {
        get { return _c.Text.Length > 0; }
    }
}
于 2008-09-26T21:32:20.687 に答える
2

簡単に言えば、Entity クラスがあり、その Entity でラムダ式を使用して、何かが有効かどうかを判断する (ブール値を返す) 場合は、Func を使用できます。

したがって、エンティティが与えられた場合:

 class Entity
 {
      public string MyProperty { get; set; }
 }

次のように ValidationRule クラスを定義できます。

 class ValidationRule<T> where T : Entity
 {
      private Func<T, bool> _rule;

      public ValidationRule(Func<T, bool> rule)
      {
           _rule = rule;
      }

      public bool IsValid(T entity)
      {
           return _rule(entity);
      }
 }

次に、次のように使用できます。

 var myEntity = new Entity() { MyProperty = "Hello World" };
 var rule = new ValidationRule<Entity>(entity => entity.MyProperty == "Hello World");

 var valid = rule.IsValid(myEntity);

もちろん、それは可能な解決策の 1 つにすぎません。

上記の一般的な制約 (「where T : Entity」) を削除すると、これを任意の POCO で使用できる一般的なルール エンジンにすることができます。必要なすべてのタイプの使用法に対してクラスを派生させる必要はありません。したがって、この同じクラスを TextBox で使用したい場合は、次を使用できます (一般的な制約を削除した後)。

 var rule = new ValidationRule<TextBox>(tb => tb.Text.Length > 0);
 rule.IsValid(myTextBox);

このようにかなり柔軟です。ラムダ式とジェネリックを一緒に使用すると、非常に強力です。Func または Action を受け入れる代わりに、Expression> または Expression> を受け入れ、Express ツリーに直接アクセスして、メソッドまたはプロパティの名前、式のタイプなどを自動的に調査することができます。クラスはコードを 1 行も変更する必要はありません。

于 2008-09-26T21:42:52.890 に答える
1

何かのようなもの:

class ValidationRule
{
    private Func<bool> validation;

    public ValidationRule(Func<bool> validation)
    {
        this.validation = validation;
    }
    public bool IsValid()
    {
        return validation();
    }
}

より C# 3 スタイルになりますが、@Frank Krueger の回答と同じコードにコンパイルされます。これはあなたが求めたものですが、正しくありません。検証を実行するためにエンティティを拡張できない正当な理由はありますか?

于 2008-09-26T21:41:17.700 に答える
0

このようなルール定義の構文はうまくいきますか?

  public static void Valid(Address address, IScope scope)
  {
    scope.Validate(() => address.Street1, StringIs.Limited(10, 256));
    scope.Validate(() => address.Street2, StringIs.Limited(256));
    scope.Validate(() => address.Country, Is.NotDefault);
    scope.Validate(() => address.Zip, StringIs.Limited(10));

    switch (address.Country)
    {
      case Country.USA:
        scope.Validate(() => address.Zip, StringIs.Limited(5, 10));
        break;
      case Country.France:
        break;
      case Country.Russia:
        scope.Validate(() => address.Zip, StringIs.Limited(6, 6));
        break;
      default:
        scope.Validate(() => address.Zip, StringIs.Limited(1, 64));
        break;
    }

詳細については、.NETでの DDD およびルール主導の UI 検証を確認してください。

于 2009-02-12T14:28:46.427 に答える