我正在实现一种流畅的构建器模式,需要在静态扩展方法中接受可枚举对象,并迭代其内容,同时对可枚举对象的内容应用函数对象。示例如下(引用的不是实际代码,仅为说明):
public static IValidator<IEnumerable<T>> Each<T>(
this IValidator<IEnumerable<T>> enumerable,
Func<T, bool> action)
{
foreach (T value in enumerable)
action(value);
return validator;
}
这对于可枚举类型来说效果非常好,但是对于继承的类型/接口则无法正常工作。比如说:
IValidator<IEnumerable<Guid>> validator = ...;
IEnumerable<Guid> guids = ...;
validator.Each(guids, guid => guid != Guid.Empty); // ok
IList<Guid> guids = ...;
validator.Each(guids, guid => guid != Guid.Empty); // doesn't compile (see below)
例外情况如下:
我的问题涉及
IValidator<IList<Guid>>
不包含“Each”的定义,而且找不到接受类型为IValidator<IList<Guid>>
的第一个参数的任何扩展方法“Each”(是否缺少使用指令或程序集引用?)
IValidator<T>
的继承链,更具体地说,涉及其泛型类型参数T
。为什么类型IValidator<IEnumerable<T>>
不能赋值给IValidator<IList<T>>
?在我看来,没有任何情况会使IList<T>
不是IEnumerable<T>
(假设它们有相同的T
)。将泛型参数限制为
T : IEnumerable<R>
可以解决问题,但这需要两个类型参数(T
和R
),如果可能的话,我想避免这种情况。有什么想法?更好的解决方案吗?谢谢。
IEnumerable<T>
是协变的,而IList<T>
不是。虽然我认为问题可能在于IValidator
本身不是协变的。你有克服这个问题的想法吗? - lsoliveiraIValidator<T>
时尝试使用IValidator<out T>
或IValidator<in T>
,我忘记了哪一个。你也可以直接使用var guids = validator.Each.....
,这可能会有所帮助,但不会解决你的设计问题。 - Jason Evansout T
使其具有协变性是关键(这是安全的,因为IValidator<T>
中类型为T
的成员没有任何变异)。 - lsoliveira