C#:强制转换为基类型的通用接口

que*_*en3 11 c# generics

这是代码:

public interface IValidator<T>
{
   bool IsValid(T obj);
}

public class OrderValidator: IValidator<Order>
{
  // ...
}

public class BaseEntity
{
}

public class Order: BaseEntity
{
}
Run Code Online (Sandbox Code Playgroud)

问题是我做不到:

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 = ... 
Run Code Online (Sandbox Code Playgroud)

如何获取并存储基础T的所有IValidator <T>实现的列表 - 比如BaseEntity?目前我做的是非通用的IValidator,接受"对象obj",但它不好,不是类型安全的.

有趣的是C#允许编译:

var test = (IValidator<BaseEntity>)new OrderValidator();
Run Code Online (Sandbox Code Playgroud)

但在运行时失败了

   Unable to cast object of type 'OrderValidator' to type 'IValidator`1[Orders.Core.BaseEntity]'
Run Code Online (Sandbox Code Playgroud)

这是Windsor给我的同样的例外(我试过Windsor和手动类型查找,这个问题与此无关,只与接口转换有关).

感谢Heinzi,我现在看到为什么我无法施放 - 因为IValidator for Order期望Order为泛型类型.但是,如何返回不同类型的IValidator列表?原因是BaseEntity采用其真实类型并收集所有验证器 - 从GetType()到对象的所有类型.我真的想要一个通用的GetValidators(),然后对它进行操作.

Hei*_*nzi 10

如果我解释为什么这个演员被禁止,也许它可以帮助你:假设你有以下功能

void myFunc(IValidator<BaseEntity> myValidator) {
    myValidator.IsValid(new BaseEntity());
}
Run Code Online (Sandbox Code Playgroud)

这段代码可以正确编译.但是,如果你传递OrderValidator给这个函数,你会得到一个运行时异常,因为OrderValidator.IsValid需要一个Order,而不是一个BaseEntity.如果您的演员被允许,将不再保持类型安全.

编辑:C#4允许通用的共同和逆变,但这对你的情况没有帮助,因为你使用T作为输入参数.因此,只能以IValidator<SomeSubtypeOfOrder>类型安全的方式进行铸造.

因此,要清楚,您无法转换OrderValidatorIValidator<BaseEntity>因为您的OrderValidator只能验证订单,而不是所有类型的BaseEntities.然而,这是预期的IValidator<BaseEntity>.