2017-03-27 21 views
0

この問題を間違った方法で解決しようとしている可能性があります。つまり、オブジェクト(つまり、引数、エンティティなど)を操作(挿入、更新、選択など)で検証する必要があります。C#検証パターン - 特定の操作でエンティティを検証するためのベストプラクティス

ここでは、1つのクラスと2つの操作に対してのみ小さなコードサンプルを作成しました。しかし、私の実際のプロジェクトでは、Personや操作のような多くのクラスがあります。

Person.cs

public class Person 
{ 
    public int Id {get;set;} 
    public string Name {get;set;} 
    public DateTime Birthdate {get;set;} 
    public BeverageSelectionType BeverageSelection {get;set;} 
} 

BeverageSelectionType.cs

public enum BeverageSelectionType 
{ 
    NotSet, 
    Juice, 
    Beer, 
    Water 
} 

IService.cs

public interface IService 
{ 
    void Update(Person person); 
    Person Add(Person person); 
} 

PersonSevice.cs(私はserviceとして選んだのが、で、それをシンプルに説明するために現実私はrepository patternUnitOfWorkを使っていますHTここに書くのは長いだろう)

public class PersonService : IService 
{ 
    public void Update(Person person) 
    { 
     if(person.BeverageSelection == BeverageSelectionType.NotSet 
      || (person.BeverageSelection == BeverageSelectionType.Beer && person.Birthdate < DateTime.Now.AddYears(-18)) 
     ) 
     throw new MyInvalidException("Parameters NOT valid for UPDATE operation"); 

     //Do update with expected parameters 
    } 

    public Person Add(Person person) 
    { 
     if(person.Birthdate <= DateTime.MinValue || person.Birthdate >= DateTime.MaxValue) 
     throw new MyInvalidException("Parameters NOT valid for ADD operation"); 

     //Do add with expected parameters 
    } 
} 

私が操作に対する実体を検証するのに役立ちます検証のための可能なアプローチとして、一般的なようなを設計する必要があります。私は各サービスにバリデーションロジックを追加したくないだけです。

Person.cs

public class Person 
{ 
     public int Id {get;set;} 
     public string Name {get;set;} 
     public DateTime Birthdate {get;set;} 
     public BeverageSelectionType BeverageSelection {get;set;} 

    public bool IsValid(ModelValidationType modelValidationType) 
    { 
     switch(modelValidationType) 
     { 
      case ModelValidationType.Update: 
       if(person.BeverageSelection == BeverageSelectionType.NotSet 
      || (person.BeverageSelection == BeverageSelectionType.Beer && person.Birthdate < DateTime.Now.AddYears(-18)) 
     ) 
      return false; 

      case ModelValidationType.Add: 
      if(person.Birthdate <= DateTime.MinValue || person.Birthdate >= DateTime.MaxValue) 
      return false; 
     } 

    return true; 
    } 
} 
:ここ

すべてのエンティティは、それが有効ですが、私も有用であったが、まだ十分ではないと信じてどのようにとき自体を知っていることを別のアプローチであります

最も適切なバリデーション手法をどのように実装しますか?

ありがとうございます。

答えて

0

私はそれを実装する方法に従います。コードの後に​​いくつかの明確化。プロパティ

オーバー

public class Person 
{ 
    private int id; 
    private DateTime birthdate; 
    private BeverageSelectionType beverageSelectionType; 

    public string Name { get; private set; } 

    public Person(string name, DateTime birthdate) 
    { 
     if(birthdate <= DateTime.MinValue || birthdate >= DateTime.MaxValue) 
      throw new ArgumentOutOfRangeException(nameof(birthdate)); 

     id = 0 
     Name = name; 
     this.birthdate = birthdate; 
    } 

    public void OrderBeverage(BeverageSelectionType beverageSelectionType) 
    { 
     if(beverageSelectionType == BeverageSelectionType.Beer $$ 
      birthdate > DateTime.Now.AddYears(-18)) 
     { 
      throw new InvalidOperationException("Person is not old enough for beer, sorry bro") 
     } 

     this.beverageSelectionType = beverageSelectionType; 
    } 
} 

1.プライベートフィールド私はいつも外には重要ではないthatsのすべてを非表示にすることをお勧めします。これは、基本的なカプセル化または情報隠蔽です。あなたが何かをパブリックにする強い理由がないなら、それをしないでください。

2.コンストラクタ

あなたの人は常に名前と誕生日を必要としているようです。そのため、私はコンストラクタでこれを保証します。無効なオブジェクトをインスタンス化する理由はありますか?いいえ - >しないでください。

3。「熱心な検証」を伴うメソッド

この例では、検証はメソッド内で行われます。これは、クライアントコードがその上で動作し、永続性がトリガーされる前に何をすべきかを決めることができるため、良いことです。

一般に、1つのクラスに2つのものを混在させます。 1つは人の概念であり、もう1つはオーダーの概念です。私はこの抽象化を破らないことを勧めます。私はあなたの人のクラスが

public bool IsAdult(); 

人とあなたの飲み物の選択を取得し、それが有効な順序であるかどうかを決定するいくつかのOrderクラスのようなものを提供することを示唆しています。

+0

ありがとうございます。私はすぐに詳細を確認します。 –

+0

もちろん、歓迎です:) – Andre

関連する問題