0

私たちのシステムには、Productさまざまなカスタムプロパティを持つ可能性のあるエンティティがあります。プロパティのセットは製品ごとに異なる場合があり、タイプのフィールドに格納されList<Property>ます。プロパティはさまざまなタイプ(strings、ints、double)であり、いくつかの特別な特性を持っている場合があります。たとえば、複数値、特定の範囲の値、指定されたリストの値などです。プロパティの値は常に次の場所に含まれます。文字列フィールドValue

現在の私の現在の問題は、これらのプロパティの検証を実装することであり、検証結果の表示の一部としてどのようなアプローチを取るかということに固執しています。私が満たさなければならない要件:-検証の結果は他のアプリケーション層で使用されるため、結果のAPIは明確で使いやすい必要があります-各エラーは明確に表現されている必要があります-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を開発する唯一の人物ではないので、そのような状況が存在することさえも防ぐような設計レベルの機能が欲しいと思います。このアプローチのもう1つの問題は、ほとんどのエラーが最終的に追加情報を必要とする場合、最終的に同じアプローチ番号1になることです。

誰かがこれらの2つのアプローチについて共有したり、より良いアプローチを提案したりする考えがありますか?ご回答いただければ幸いです。前もって感謝します。

4

2 に答える 2

0

FluentValidationのようなものを見てみることをお勧めします。軽量で直感的で、多くの検証シナリオをカバーします。

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

于 2012-03-05T09:28:37.350 に答える
0

一歩下がって、「検証エラーを表す複数のクラス」アプローチ全体を再考することをお勧めします。これは、バリデーターの階層がすでに存在することがほぼ保証されているためです。

次の場合、検証エラーを完全に指定できます。

  1. プロパティの値を受け入れることができなかったバリデーター
  2. プロパティの名前
  3. 検証に失敗した値

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

では、次のような検証エラークラスを1つだけ持つのはどうでしょうか。

public sealed class ValidationError
{
    public Validator Validator { get; set; }
    public string PropertyName { get; set; }
    public object AttemptedValue { get; set; }
}
于 2012-03-05T09:19:27.880 に答える