C# 基于泛型接口的扩展方法
我正在实现一个fluent builder模式,该模式要求在静态扩展方法中接受可枚举项并遍历其内容,同时对可枚举项的内容应用函子。如中所示(不是实际代码,只是一个示例):C# 基于泛型接口的扩展方法,c#,.net,generics,extension-methods,ienumerable,C#,.net,Generics,Extension Methods,Ienumerable,我正在实现一个fluent builder模式,该模式要求在静态扩展方法中接受可枚举项并遍历其内容,同时对可枚举项的内容应用函子。如中所示(不是实际代码,只是一个示例): 每个公共静态IValidator( 此IValidator可枚举, (职能行动) { foreach(可枚举中的T值) 作用(价值); 返回验证器; } 这对可枚举项非常有效,但对继承的类型/接口无效。比如说: IValidator<IEnumerable<Guid>> validator = ...
每个公共静态IValidator(
此IValidator可枚举,
(职能行动)
{
foreach(可枚举中的T值)
作用(价值);
返回验证器;
}
这对可枚举项非常有效,但对继承的类型/接口无效。比如说:
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验证程序=。。。;
IEnumerable GUID=。。。;
每个(guid,guid=>guid!=guid.Empty);//好啊
IList guids=。。。;
每个(guid,guid=>guid!=guid.Empty);//未编译(请参见下文)
例外情况是:
IValidator
不包含“每个”的定义
并且没有扩展方法“Each”接受类型为的第一个参数
IValidator
可以找到(您是否缺少使用
指令还是程序集引用
我的问题是关于IValidator
的继承链,更具体地说,是关于它的泛型类型参数T
。为什么类型IValidator
不能从IValidator
赋值?我想不出在什么情况下IList
不是IEnumerable
(给定相同的T
)
将泛型参数约束为T:IEnumerable
确实有效,但这需要两种类型的参数(T
和R
),如果可能的话,我希望避免使用这两种类型的参数
有什么想法吗?更好的解决方案吗?谢谢。这是由于您的
IValidator
界面的定义。我敢打赌这是一个大致如下的东西:
public interface IValidator<T>
这将表明T
应源自IEnumerable
两个答案:
where T:IEnumerable
是完全合法的,它可以解决您的问题,并且不需要第二个泛型类型ivalidtor
不可从ivalidtor
分配,因为您的接口不是变体。从v4开始,C#确实支持接口变体,但您必须在接口定义中明确要求它。为此,请参阅请注意,由您来确保您的接口确实是变体安全的。这就是为什么在C#4之前它不可能实现的原因,因为它并不总是有效的;有些接口是安全协变的,有些是安全逆变的(您只能用较少的派生类型替换期望的类型)。这一切都取决于你在做什么。我认为这可能是协方差和逆变问题。让我看看是否可以获得一些示例代码,看看这是否正确。即使你解决了当前的问题,该方法的意义何在?你没有使用传入的函子的布尔结果,因此除非函子对对象进行变异,否则net结果没有任何变化,如果它确实对它进行了变异,那么……嗯……它不应该发生变化,因为Linq是为查询而设计的,而不是为序列变异而设计的。@Servy-这只是一个示例来说明我的意图,而不是实际的代码。我将其保留为
Func
,因为它在考试中编写调用lambda所需的代码少于操作
下面是例子。我有点懒。:-)IEnumerable(使用.NET4+)是协变的,但IList不是,因为后者同时使用输入和输出参数。好吧,我没有时间编写一些代码。我的建议是,当您使用IValidator
尝试IValidator
或IValidator
时,我忘了是哪一个。您也可以只使用var guids=validator。每个..
可以使用哪一个lp,尽管它不会消除您的设计问题。在上面@JasonEvans的评论之后,我记得我完全忘记了co/逆变。您说得对。使界面协变解决了问题。感谢您的输入。
public interface IValidator<T>
public interface IValidator<out T>
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;
}