我在使用泛型和C#编写代码时遇到了一些麻烦 [英] I'm having some trouble with generics and casting in C#

查看:112
本文介绍了我在使用泛型和C#编写代码时遇到了一些麻烦的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我有一个简单的验证规则模式,用于对实体对象进行验证。这里是我的ValidationRule类:

  public class ValidationRule {

public Func< object,bool>规则{get;组; }
public string ErrorMessage {get;组; }

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


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




$ b我有一个用于封装我的实体对象的基类执行验证的方法如下所示:

  public abstract class ModelBase {

private List<有效性规则> _validationRules;
public List< ValidationRule> ValidationRules {
获得{
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));
});
返回结果;
}
}

现在,我正在尝试的是真正的问题解决。当我创建一个从ModelBase继承的新类时,添加验证规则有点尴尬。例如:

  public class Client:ModelBase {

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

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> 这样的通用方法,但我总是遇到调用 Validate()。关于如何解决这个转型的任何想法?

解决方案

您可以使ValidationRule类具有通用性,但保留IsValid方法作为对象并在该方法中进行投射。这样你就可以获得泛型,而无需使ModelBase成为泛型。



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



(注意:您可以在属性上使用私有setter来使其成为只读。 )

  public Interface IValidationRule {
bool IsValid(object);
}

公共类ValidationRule< T> :IValidationRule {

public Func< T,bool>规则{get;私人设置; }
public string ErrorMessage {get;私人设置; }

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


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


$ / code $ / pre

现在,lamda表达式中的参数类型是通用类型,因此您不必投射它:

  ValidationRules.Add(
new ValidationRule<客户端>(
客户端名称是必需的。,
c =>!string.IsNullOrEmpty(c.Name)

);


So I have a simple validation rule pattern that I'm using to do validation on entity objects. Here is my ValidationRule class:

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);
    }
}

I have a base class for my entity objects that encapsulate the methods to perform validation that looks like this:

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;
    }
}

And now here's the real problem I'm trying to solve. When I create a new class that inherits from ModelBase adding validation rules is a little awkward. For example:

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)));
    }
}

Notice where I'm creating the validation rules list. Inside the lambda expression I have to cast "c" to "Client" because my rule is essentially Func<object, bool>. I've tried many ways to make this generic by doing something like ValidationRule<Client> but I always run into problems with calling Validate() in the ModelBase class. Any ideas on how to get around this casting?

解决方案

You can make the ValidationRule class generic, but leave the parameter for the IsValid method as object and do the casting in the method. That way you get the generics without having to make ModelBase generic also.

You also need an interface for the ModelBase to be able to keep a list of validation rules without knowing their actual type. Then just change the type of the list and the property in ModelBase to IValidationRule.

(Note: You can use a private setter on the properties to make them read-only.)

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);
    }
}

Now, the type of the parameter in the lamda expression is the generic type, so you don't have to cast it:

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

这篇关于我在使用泛型和C#编写代码时遇到了一些麻烦的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆