0


0

ジェネリックとC#でのキャストに問題があります。

だから私はエンティティオブジェクトの検証をするために使っている簡単な検証ルールパターンを持っています。 これが私のValidationRuleクラスです:

public class ValidationRule {

    public Func Rule { get; set; }
    public string ErrorMessage { get; set; }

    public ValidationRule(string errorMessage, Func rule) {
        Rule = rule;
        ErrorMessage = errorMessage;
    }

    public bool IsValid(object obj) {
        return Rule(obj);
    }
}

私はこのように見える検証を実行するためにメソッドをカプセル化する私のエンティティオブジェクトのための基本クラスを持っています:

public abstract class ModelBase {

    private List _validationRules;
    public List ValidationRules {
        get {
            if (_validationRules == null)
                _validationRules = new List();
            return _validationRules;
        }
        set { _validationRules = value; }
    }

    public ValidationResult Validate() {
        var result = new ValidationResult();
        rules.ForEach(r => {
            if (!r.IsValid(this))
                result.Errors.Add(
                    new ValidationError(r.ErrorMessage, r.PropertyName));
            });
        return result;
    }
}

そして今、これが私が解決しようとしている本当の問題です。 ModelBaseから継承する新しいクラスを作成するときに検証規則を追加するのは少し面倒です。 例えば:

public class Client : ModelBase {

    public int ID{ get; set; }
    public string Name { get; set; }
    public Address MailingAddress { get; set; }

    public Client() {
        CreateValidationRules();
    }

    private void CreateValidationRules() {

        ValidationRules.Add(new ValidationRule("Client 'Name' is required.",
            c => !string.IsNullOrEmpty(((Client)c).Name)));
    }
}

検証規則リストを作成している場所に注目してください。 私のルールは基本的に Func`なので、ラムダ式の中では" c "を" Client "にキャストする必要があります。 私は `ValidationRule`のようなことをすることによってこのジェネリックを作るために多くの方法を試みましたが、私は常にModelBaseクラスの中で Validate() `を呼び出すことに関する問題に出くわします。 このキャスティングを回避する方法について何かアイデアはありますか?

2 Answer


4


ValidationRuleクラスを汎用にすることはできますが、IsValidメソッドのパラメーターをオブジェクトのままにして、メソッド内でキャストを行うことができます。 そうすれば、ModelBaseを一般的なものにする必要もなく、総称を取得できます。

実際の型を知らなくても検証規則のリストを保持できるようにするには、ModelBaseのインターフェイスも必要です。 次に、ModelBaseのリストのタイプとプロパティをIValidationRuleに変更します。

(注:プロパティにプライベートセッターを使用してそれらを読み取り専用にすることができます。)

パブリックインターフェイスIValidationRule {bool IsValid(オブジェクト); }

パブリッククラスValidationRule:IValidationRule {

公開関数ルール{get;プライベートセットパブリック文字列ErrorMessage {get;}プライベートセット}

public ValidationRule(文字列errorMessage、Func rule){Rule = rule; ErrorMessage = errorMessage; }

公開bool IsValid(オブジェクトobj){戻りルール((T)obj); }}

これで、lamda式のパラメータの型は総称型なので、キャストする必要はありません。

ValidationRules.Add(new ValidationRule( "クライアント '名前'は必須です。"、c =>!string.IsNullOrEmpty(c.Name)));


1


私はModelBaseも一般的になる必要があると思います。 しかし、ここで何が行われているのか正確にはわかりません - すべてのクライアントで検証規則が同じになるのではないでしょうか。 検証規則は、型の個々のインスタンスではなく、型全体に関連付けられるべきであると感じます。 確かに、それらは単一のインスタンスに対して「検証」されるでしょう。

私はあなたが Validator`型を持つべきではないかと疑問に思います、そして Client`の任意のインスタンスに対して検証することができる `Validator`を(一度)作成します。