我在 C# 中的泛型和转换方面遇到了一些问题

JC *_*bbs 0 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在这就是我想要解决的真正问题。当我创建一个继承自 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)));
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意我在哪里创建验证规则列表。在 lambda 表达式中,我必须将“c”转换为“Client”,因为我的规则本质上是Func<object, bool>. 我已经尝试了很多方法来通过执行类似的操作来使其通用,但我总是在调用 ModelBase 类时ValidationRule<Client>遇到问题。Validate()关于如何绕过这个选角有什么想法吗?

Guf*_*ffa 5

您可以使 ValidationRule 类通用,但将 IsValid 方法的参数保留为对象,并在该方法中进行转换。这样您就可以获得泛型,而不必使 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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