错误实例化Generic类

时间:2014-08-16 07:12:59

标签: c# validation generics

我正在创建C#windows应用程序并使用FluentValidation来验证视图模型。在每种形式中,我总是创建这样的验证方法:

private bool ValidateCustomer(CustomerViewModel customerVM)
{
    CustomerValidator validator = new CustomerValidator();
    ValidationResult results = validator.Validate(customerVM);

    if (!results.IsValid)
    {
        StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");

        foreach (var failure in results.Errors)
        {
            errorMessage.AppendLine("- " + failure.ErrorMessage);
        }

        MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        return false;
    }

    return true;
}

public class CustomerValidator : AbstractValidator<CustomerViewModel>
{
    public CustomerValidator()
    {
        RuleFor(c => c.Code).NotEmpty();
        RuleFor(c => c.Name).NotEmpty();
    }
}

我想创建Generic ValidationHelper类,以便我不会在每种形式中编写相同的验证代码(只是不同的验证器和viewmodel类),例如: ValidationHelper<MyValidator, MyViewModel>.Validate()。我只是替换另一个表单的MyValidator和MyViewModel类。当make这个Generic类时,我在实例化验证器类时遇到了问题。

public static class ValidatorHelper<T, V> 
        where T : class, new() 
        where V : class, new()
    {
        public static bool Validate(T t, V n)
        {
            T validator = new T(); 
            ValidationResult results = validator.Validate(n); // <--- error on this line

            if (!results.IsValid)
            {
                StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");

                foreach (var failure in results.Errors)
                {
                    errorMessage.AppendLine("- " + failure.ErrorMessage);
                }

                MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return false;
            }

            return true;
        }
    }

如何解决这个问题?

更新

作为@JonSkeet和@dbc建议,我将ValidatorHelper修改为:

public static class ValidatorHelper<T, V>
    where T : AbstractValidator<V>, new()
    where V : class, new()
{
    public static bool Validate(V v)
    {
        T validator = new T();
        ValidationResult results = validator.Validate(v);

        if (!results.IsValid)
        {
            StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");

            foreach (var failure in results.Errors)
            {
                errorMessage.AppendLine("- " + failure.ErrorMessage);
                //log.Message("Property " + failure.PropertyName + " failed validation. Error was: " + failure.ErrorMessage);
            }

            MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return false;
        }

        return true;
    }
}

我没有在public static bool Validate(V v)上使用T,因为它会在其中实例化。然后在表格上,您只需写下:

if (ValidatorHelper<CustomerValidator, CustomerViewModel>.Validate(customerVM))

多亏了你们两个,我可以解决问题,我真的很感激。

2 个答案:

答案 0 :(得分:3)

您尝试为CustomerValidator类型的变量分配T引用。如果TStringBuilder或类似的内容会怎样?

从根本上说,ValidationHelper声称是通用的,但后来具体CustomerValidator似乎很奇怪。

在不知道FluentValidation库的情况下,我们真的不知道CustomerValidator做了什么 - 它是否实现了Validator<Customer>?我想你可能想要将验证器传递给Validate方法或ValidatorHelper构造函数。 (我强烈怀疑你想要摆脱静态修饰符的两个 - 如果方法是静态的,它不能在基类中实现抽象方法......如果是类是静态的,它甚至不能特定基类。)

从根本上说,你需要考虑:

  • 应该了解CustomerValidator?可能不是通用助手类。
  • 应该创建验证器的内容?选项:
    • 帮助程序本身(可能使用new()约束)
    • 创建帮助程序实例的调用者,假设您将拥有实例
    • 无论如何调用您的Validate方法

可能想要这样的东西:

// No constraint on V - why would you need one?
public class ValidatorHelper<T, V> : AbstractValidator<V> 
        where T : AbstractValidator<V>
{
    public bool Validate(T validator, V value)
    {
        ValidationResult results = validator.Validate(value);

        if (!results.IsValid)
        {
            StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");

            foreach (var failure in results.Errors)
            {
                errorMessage.AppendLine("- " + failure.ErrorMessage);
            }

            MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return false;
        }

        return true;
    }
}

答案 1 :(得分:1)

一个问题是,您的约束并不表示T来自CustomerValidator

where T : class, CustomerValidator, new() 

但究竟是什么CustomerValidator?它是一些抽象基类,将为每个验证要求进行子类化吗?如果是这样,旧代码中的new CustomerValidator()将无效。

如果CustomerValidator是一些新创建的抽象基类,为了清楚起见,您可以考虑提取一个接口,如下所示:

public interface IValidator<V> 
{
    ValidationResult Validate(V data); 
}

基本上,这是一个验证任何内容的类的接口,将结果返回到ValidationResult对象中。

一旦有了用于返回某些内容的验证结果的标准界面,您的静态帮助程序将变为:

public static class ValidatorHelper<T, V> 
    where T : class, IValidator<V>, new()
    where V : class, new()
{
    public static bool Validate(T t, V n)
    {
        T validator = new T(); 

        ValidationResult results = validator.Validate(n);

        if (!results.IsValid)
        {
            StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");

            foreach (var failure in results.Errors)
            {
                errorMessage.AppendLine("- " + failure.ErrorMessage);
            }

            MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return false;
        }

        return true;
    }
}