繁体   English   中英

如何在C#中的通用接口上创建协变扩展方法?

[英]How can I create a covariant extension method on a generic interface in C#?

如果标题没有意义,这是一个例子:

interface IEat { void Eat; }
class Cat : IEat { void Eat { nom(); } }
class Dog : IEat { void Eat { nom(); nom();nom(); } }
class Labrador : Dog { }

我想创建一个像这样的扩展方法:

public static void FeedAll(this IEnumerable<out IEat> hungryAnimals) {
   foreach(var animal in hungryAnimals) animal.Eat();
}

所以我可以这样做:

listOfCats.FeedAll();
listOfLabs.FeedAll();
listOfMixedHungryAnimals.FeedAll();

这可能吗? 我哪里做错了?

这里真实的应用程序是“Dog”是我的应用程序中的主要基类,并且有许多子类,每个子类可能不时有IList,需要对它们执行组操作。 必须将它们转换为在它们全部实现的接口List上调用扩展方法将是次优的。

编辑:

我稍微讨论了这个例子。 我的实际代码是使用IList ,我希望可以使用Count和基于索引的操作。 基于下面的答案,我想我将不得不为需要IList语义的方法寻找另一个方向。

这将删除out

public static void FeedAll(this IEnumerable<IEat> hungryAnimals) {
   foreach(var animal in hungryAnimals) animal.Eat();
}

方差应用于接口本身(的参数TIEnumerable<T>在这种情况下),这样一个List<Dog>是兼容IEnumerable<IEat>

IEnumerable已经是协变的,因此您的扩展方法可以接受IEnumerable<IEat> ,并且IEnumerable<Dog>实例将是一个有效的参数,使得扩展方法适用于这些类型的变量。

如果接口的定义没有指定泛型参数是协变/逆变,那么扩展方法可以做的任何事情都不允许该参数是协变的。 如果您使用的是一个不变的List ,那么您的扩展方法无法允许使用协方差。

正如Servy所说, Enumerable<T>已经是协变的,但它并不需要。 对于界面不协变的旧版本,您可以这样做:

public static void FeedAll<T>(this IEnumerable<T> hungryAnimals) where T : IEat
{
    foreach(var animal in hungryAnimals) animal.Eat();
}

你不需要它通过引用传递它所以它将解决它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM