lso*_*ira 5 .net c# generics ienumerable extension-methods
我正在实现一个流畅的构建器模式,它需要在静态扩展方法中接受可枚举并迭代其内容,同时将一个仿函数应用于可枚举的内容.如(不是实际代码,只是一个例子):
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;
}
Run Code Online (Sandbox Code Playgroud)
这对于枚举非常有效,但对于继承的类型/接口则失败.让我们说:
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)
Run Code Online (Sandbox Code Playgroud)
例外是:
IValidator<IList<Guid>>不包含'Each'的定义,也没有扩展方法'each'接受类型的第一个参数IValidator<IList<Guid>>可以找到(你是否缺少using指令或汇编引用?
我的问题是关于继承链IValidator<T>,更具体地说,是它的泛型类型参数T.为什么类型IValidator<IEnumerable<T>>不可分配IValidator<IList<T>>?没有任何情况我可以想到哪个IList<T>不是IEnumerable<T>(给定相同T).
约束泛型参数T : IEnumerable<R>确实有效,但是如果可能的话,这需要两个我想避免的类型参数(T和R).
有什么想法吗?好的解决方案 谢谢.
这是由于您的IValidator<T>界面的定义.我敢打赌它是这样的:
public interface IValidator<T>
Run Code Online (Sandbox Code Playgroud)
你真正想要的是:
public interface IValidator<out T>
Run Code Online (Sandbox Code Playgroud)
这将使您的接口协变,这意味着您可以分配IValidator<T2>to 的实现IValidator<T>,假设T2派生自T.
在这种情况下,IList<T>派生自IEnumerable<T>,所以你应该能够声明T为协变.但是,这取决于IValidator<T>它们的暴露方法和方式.
也就是说,如果您有方法将接口的IValidator<T>实例T作为接口上的任何方法的参数,那么您将无法将接口声明为协变.
如果是这种情况,那么你应该能够摆脱这个定义Each:
public static IValidator<T> Each<T, TValue>(
this IValidator<T> enumerable,
Func<TValue, bool> action) where T : IEnumerable<TValue>
{
foreach (TValue value in enumerable)
action(value);
return validator;
}
Run Code Online (Sandbox Code Playgroud)
这表明T应该来自IEnumerable<TValue>.
| 归档时间: |
|
| 查看次数: |
1638 次 |
| 最近记录: |