2012-03-05 10 views
0

私たちのシステムには、さまざまなカスタムプロパティを持つ可能性があるエンティティProductがあります。プロパティのセットは製品ごとに異なる場合があり、タイプList<Property>のフィールドに格納されます。プロパティは異なる型(文字列、int、double)であり、いくつかの特殊な特性を持つかもしれません。それらは多値でもよく、特定の範囲の値でもよいし、指定されたリストなどからの値でもよい。プロパティの値は常に文字列フィールドValueに含まれる。検証エラー階層設計

現在、私の現在の問題はこれらのプロパティの検証を実装することであり、検証結果の表現の一環としてどのようなアプローチを取っているのでしょうか。私が満足しなければならない要件: - 検証の結果は他のアプリケーション層で使用されるので、結果として得られるAPIは明確で使いやすいものにしてください - それぞれのエラーには別個の表現が必要です -

  1. クラス:エラーの詳細を理解するための情報(例えば、彼らは最小限の可能な値、最大可能値と実際の値に提供されるべき範囲エラー用)

    ここでは、私がこれまで考えられてきたアプローチがあります階層。 1つの基本抽象クラスValidationErrorがあり、それぞれの特定のエラーは継承クラスに反映されます。エラーに詳細がある場合、対応するクラスにはすべての情報を格納するために必要なフィールドがあります。例:

    public abstract class ValidationError 
    { 
        // common fields and methods, if any 
    } 
    
    public class IncorrectFormatValidationError : ValidationError 
    { 
        // just empty class, nothing to add here 
    } 
    
    public class RangeValidationError : ValidationError 
    { 
        public object MinValue { get; set; } 
    
        public object MaxValue { get; set; } 
    } 
    

    このアプローチは、実際には空のクラスの多様性のために私にとっては冗長なようです。そのようなAPIの使用法は正しいとは思われません(if (typeof(error) == typeof(RangeValidationError)) - ナンセンス!)。しかし、これは私の頭に来た最初のことです。

  2. エラー列挙型、必要な場合はクラス階層型。すべてのエラーは列挙で表されます。ほとんどの場合に使用される1つのクラスValidationErrorがあり、特定のエラーに追加情報が必要な場合は、基本的に最初の方法と同じ方法で継承者が作成されます。例:

    public enum ValidationErrors 
    { 
        IncorrectFormat, 
        ValueNotWithinRange, 
        ... 
    } 
    
    public class ValidationError 
    { 
        public ValidationErrors ErrorType { get; set; } 
    
        public ValidationError(ValidationErrors type) 
        { 
         this.ErrorType = type; 
         ... 
        } 
    
        // common fields and methods, if any 
    } 
    
    public class RangeValidationError : ValidationError 
    { 
        public object MinValue { get; set; } 
    
        public object MaxValue { get; set; } 
    
        public RangeValidationError(object minValue, object maxValue) : 
         base(ValidationErrors.ValueNotWithinRange) 
        { 
         ... 
        } 
    } 
    

    このアプローチは、はるかに優れていますが、欠点もあります。最大の問題は、APIのユーザーとして、タイプがValueNotWithinRangeのエラーが発生した場合、タイプRangeValidationErrorのクラスを扱っていることを保証できないことです。そうでない場合はどうしますか?私はAPIを開発しているonylではないので、このような状況が存在することさえ防止する設計レベルの機能を持っていたいと思います。このアプローチのもう一つの問題は、ほとんどのエラーが最後にいくつかの追加情報を必要とする場合は、我々は最終的に同じaprroach番号1

になってしまいますということです。誰でもこの2つの方法で共有するために、任意の考えを持っていますか、より良いものをお勧めしますか?私はどんな応答も高く評価します。前もって感謝します。

答えて

0

バックステップを取ると、ほとんどあなたがすでにバリの階層構造を持っていることを保証しているため全体の「検証エラーを表す複数のクラス」のアプローチを、再考する良いアイデアかもしれません。

どれ検証エラーが完全に与え指定することができます: を検証するために失敗したプロパティ

  • プロパティ
  • 値の名前の値を受け入れることができなかった

    1. バリ

      これ以上の情報(範囲の制限、一致しなかった正規表現など)はすでにバリデータインスタンスに存在し、それを介してアクセスできます。

      だから、このようになりますちょうど1検証エラークラスを持っていることについてどのような:

      public sealed class ValidationError 
      { 
          public Validator Validator { get; set; } 
          public string PropertyName { get; set; } 
          public object AttemptedValue { get; set; } 
      } 
      
  • +0

    実際、この方法で階層の重複を避けることができますが、抽象的なValidatorの追加ダウンキャスティングも導入します。 Validatorを型パラメータに変更することを提案します。 – Basilevs

    +0

    @Basilevs:階層ルートに存在しないメンバーにアクセスする必要がある場合は(たとえ 'Min'や' Max'プロパティなど)、ダウンキャストが必要になります( 'ValidationError'階層でさえ)。唯一の他の方法は、実行時に動的にプロパティ値にアクセスする機能を構築することです。リフレクションを使用することと同じ道徳的なもので、基本的な問題は同じです:型の安全性の損失です。 – Jon

    +0

    @ジョン、応答のおかげで。いいえ、私は今までバリデーターを持っていません。すべての検証はいくつかのBLレベルの方法で行われます。しかし、彼らの紹介について考えてみる価値はありますか?しかし、もしそうなら、私たちはエラーと同じ問題に直面しています(質問に記載されています)、そうではありませんか? – Andrei

    0

    あなたはFluentValidationのようなものを見てみたいことがあります。軽量で直感的で、多くの検証シナリオをカバーしています。

    FluentValidationで使用されている検証結果が満足できない場合は、独自のカスタム検証エラークラスでラップすることができます。少なくとも、無料で多くの基本機能を利用できます。