我正在创建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))
多亏了你们两个,我可以解决问题,我真的很感激。
答案 0 :(得分:3)
您尝试为CustomerValidator
类型的变量分配T
引用。如果T
是StringBuilder
或类似的内容会怎样?
从根本上说,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;
}
}