我在使用泛型和使用C#进行转换时遇到了一些麻烦

时间:2009-02-21 19:12:40

标签: c# generics

所以我有一个简单的验证规则模式,我用它来对实体对象进行验证。这是我的ValidationRule类:

public class ValidationRule {

    public Func<object, bool> Rule { get; set; }
    public string ErrorMessage { get; set; }

    public ValidationRule(string errorMessage, Func<object, bool> rule) { 
        Rule = rule;
        ErrorMessage = errorMessage;
    }

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

我有一个实体对象的基类,它封装了执行如下所示验证的方法:

public abstract class ModelBase {

    private List<ValidationRule> _validationRules;
    public List<ValidationRule> ValidationRules {
        get {
            if (_validationRules == null)
                _validationRules = new List<ValidationRule>();
            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)));
    }
}

请注意我在哪里创建验证规则列表。在lambda表达式中,我必须将“c”转换为“Client”,因为我的规则基本上是Func<object, bool>。我已经尝试了很多方法通过像ValidationRule<Client>之类的东西来制作这个泛型,但我总是遇到在ModelBase类中调用Validate()的问题。关于如何绕过这个演员的任何想法?

2 个答案:

答案 0 :(得分:4)

您可以使ValidationRule类通用,但将IsValid方法的参数保留为对象并在方法中执行转换。这样你就可以获得泛型而无需使用ModelBase泛型。

您还需要一个ModelBase接口,以便能够在不知道其实际类型的情况下保留验证规则列表。然后只需将列表的类型和ModelBase中的属性更改为IValidationRule。

(注意:您可以在属性上使用私有设置器将它们设置为只读。)

public Interface IValidationRule {
   bool IsValid(object);
}

public class ValidationRule<T> : IValidationRule {

    public Func<T, bool> Rule { get; private set; }
    public string ErrorMessage { get; private set; }

    public ValidationRule(string errorMessage, Func<object, bool> rule) { 
        Rule = rule;
        ErrorMessage = errorMessage;
    }

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

现在,lamda表达式中的参数类型是泛型类型,因此您不必强制转换它:

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

答案 1 :(得分:1)

我怀疑ModelBase也需要变得通用。我不清楚这里到底发生了什么 - 对于每个客户端,验证规则是否相同?验证规则感觉它们应该与整个类型相关联,而不是与类型的单个实例相关联。无可否认,它们将针对单个实例进行验证

我想知道您是否应该使用Validator<T>类型,并创建(一次)Validator<Client>,然后可以对Client的任何实例进行验证。