这是代码:
public interface IValidator<T>
{
bool IsValid(T obj);
}
public class OrderValidator: IValidator<Order>
{
// ...
}
public class BaseEntity
{
}
public class Order: BaseEntity
{
}
问题是我做不到:
var validator = new OrderValidator();
// this line throws because type can't be converted
var baseValidator = (IValidator<BaseEntity>)validator;
// all this is because I need a list with IValidator<Order>, IValidator<BaseOrder>, etc.
IList<IValidator<BaseEntity>> allValidators = ...
如何获取并存储基础T的所有IValidator <T>实现的列表 - 比如BaseEntity?目前我做的是非通用的IValidator,接受“对象obj”,但它不好,不是类型安全的。
有趣的是C# 允许 编译:
var test = (IValidator<BaseEntity>)new OrderValidator();
但在运行时失败了
Unable to cast object of type 'OrderValidator' to type 'IValidator`1[Orders.Core.BaseEntity]'
这是Windsor给我的同样的异常(我试过Windsor和手动类型查找,这个问题实际上与此无关,只与接口转换有关)。
感谢Heinzi,我现在看到为什么我无法施放 - 因为IValidator for Order期望Order为泛型类型。但是,如何返回不同类型的IValidator列表?原因是BaseEntity采用其真实类型并收集所有验证器 - 从GetType()到对象的所有类型。我真的想要一个通用的GetValidators(),然后对它进行操作。
如果我解释为什么禁止这个演员,也许它可以帮助你:假设你有以下功能
void myFunc(IValidator<BaseEntity> myValidator) {
myValidator.IsValid(new BaseEntity());
}
这段代码可以正确编译。不过,如果你通过了 OrderValidator
对于这个函数,你会得到一个运行时异常,因为 OrderValidator.IsValid
期望订单,而不是BaseEntity。如果您的演员被允许,将不再保持类型安全。
编辑:C#4允许 通用的共同和逆变,但这对你的情况没有帮助,因为你用T作为 输入 参数。因此,只有铸造到 IValidator<SomeSubtypeOfOrder>
可以以类型安全的方式完成。
所以,要清楚,你不能施展 OrderValidator
至 IValidator<BaseEntity>
因为OrderValidator只能验证订单,而不能验证所有类型的BaseEntities。然而,这是预期的 IValidator<BaseEntity>
。
演员不行,因为 IValidator<Order>
和 IValidator<BaseEntity>
完全不相关的类型。 IValidator<Order>
不是的子类型 IValidator<BaseEntity>
,所以他们不能演员。
C#支持多接口继承,因此处理此问题的最简单方法是使订单验证器从两个验证器类型的接口继承,这样您就可以根据需要将其转换为任一接口。显然,这意味着你必须实现两个接口并指定如何处理基数 BaseEntity
提供的验证程序的类型不匹配。
像这样的东西:
public class OrderValidator : IValidator<Order>, IValidator<BaseEntity>
{
public bool IsValid(Order obj)
{
// do validation
// ...
return true;
}
public bool IsValid(BaseEntity obj)
{
Order orderToValidate = obj as Order;
if (orderToValidate != null)
{
return IsValid(orderToValidate);
}
else
{
// Eiter do this:
throw new InvalidOperationException("This is an order validator so you can't validate objects that aren't orders");
// Or this:
return false;
// Depending on what it is you are trying to achive.
}
}
}
这涉及到什么 Heinzi 说不能投,因为 IValidator<BaseEntity>
需要能够验证 BaseEntities
,你当前的 OrderValidator
做不到。通过添加此多个接口,您可以明确定义验证行为 BaseEntities
(通过明确地忽略它或导致异常),使得演员成为可能。
虽然这不会直接回答您,但我建议您查看StructureMap的源代码,它们可以使用开放的泛型类型。实际上甚至可能想使用StructureMap来处理验证器的缓存,这正是我所做的。
ForRequestedType(typeof (ValidationBase<>)).CacheBy(InstanceScope.Singleton);
Scan(assemblies =>
{
assemblies.TheCallingAssembly();
assemblies.AddAllTypesOf(typeof(IValidation<>));
});
然后我有一个工厂类来进行实际验证
public static class ValidationFactory
{
public static Result Validate<T>(T obj)
{
try
{
var validator = ObjectFactory.GetInstance<IValidator<T>>();
return validator.Validate(obj);
}
catch (Exception ex)
{
...
}
}
}
编辑: 我写了一篇关于使用IoC进行泛型验证的大博文,如果你看一下,因为你说你已经使用过Spring,我打赌你可以调整我的工作来解决你的问题: 创建通用验证框架