Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基于泛型接口的扩展方法_C#_.net_Generics_Extension Methods_Ienumerable - Fatal编程技术网

C# 基于泛型接口的扩展方法

C# 基于泛型接口的扩展方法,c#,.net,generics,extension-methods,ienumerable,C#,.net,Generics,Extension Methods,Ienumerable,我正在实现一个fluent builder模式,该模式要求在静态扩展方法中接受可枚举项并遍历其内容,同时对可枚举项的内容应用函子。如中所示(不是实际代码,只是一个示例): 每个公共静态IValidator( 此IValidator可枚举, (职能行动) { foreach(可枚举中的T值) 作用(价值); 返回验证器; } 这对可枚举项非常有效,但对继承的类型/接口无效。比如说: IValidator<IEnumerable<Guid>> validator = ...

我正在实现一个fluent builder模式,该模式要求在静态扩展方法中接受可枚举项并遍历其内容,同时对可枚举项的内容应用函子。如中所示(不是实际代码,只是一个示例):

每个公共静态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;
    }