Using covariance outside the context of IEnumerable<T>

本文关键字:lt gt IEnumerable of covariance outside the context Using | 更新日期: 2023-09-27 17:49:44

可能重复:
C#支持返回类型协方差吗
为什么我不能用这种方式实现接口?

考虑以下内容:

public interface IAnimal {
}
public class Animal : IAnimal {
}
public interface ICage {
     IAnimal SomeAnimal {get;}
}
public class Cage : ICage{
     public Animal SomeAnimal { get; set; }
}

我已经读了很多关于IEnumerable的协方差和反方差的东西,但我不确定如何让上面的代码发挥作用。我得到错误"Cage不实现接口成员IAnimal"。既然它定义了Animal,它比IAnimal更具定义性,似乎协方差应该照顾好我

我错过了什么?提前谢谢。

Using covariance outside the context of IEnumerable<T>

这在C#中目前是不可能的。

理论上,语言设计者可以添加它,但他们还没有。他们可能会也可能不会决定将其添加到未来可能的C#版本中。

最好的解决方法可能是:

public class Cage : ICage
{
    public Animal SomeAnimal { get; set; }
    IAnimal ICage.SomeAnimal
    {
        get { return SomeAnimal }
    }
}

引用自Eric Lippert,以回应我在这里提出的相同问题:为什么可以';我不能用这种方式实现接口吗?

C#不支持用于接口实现或虚拟方法重写。看看这个详细问题:

C#支持返回类型协方差吗?

C#确实支持接口的通用协方差和反方差和使用的引用类型构造的委托类型从C#4开始键入参数。

在转换方法时,C#确实支持返回类型协方差返回对返回类型为的委托类型的引用类型兼容的引用类型。(同样,它支持参数类型相反。(

如果你感兴趣的话,我已经写了很多文章讨论C#所做和不做的各种版本的差异支持参见

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+和+反方差/

详细信息。

要获得协方差,应该有这样的东西:

public interface IAnimal {
}
public class Lion : IAnimal {}
public class Sheep : IAnimal {}
// note the "out" on the T type parameter
public interface ICage<out T> where T:IAnimal {
     T SomeAnimal {get;}
}
public class Cage<T> : ICage<T> where T:IAnimal {
     public T SomeAnimal { get; set; }
}

你现在可以这样做了:

// without covariance on ICage you can't assign a 'Cage<Sheep>' to 'ICage<IAnimal>'
ICage<IAnimal> sheeps = new Cage<Sheep>() {SomeAnimal=new Sheep()};
ICage<IAnimal> lions = new Cage<Lion>() {SomeAnimal=new Lion()};

或者这个(创建一个具有羊笼和狮子笼的Cage<IAnimals>的异构列表(,这是一个等效但可能更有用的例子:

// without covariance on ICage it errors: cannot convert from 'Cage<Sheep>' to 'ICage<IAnimal>'
var zoo = new List<ICage<IAnimal>>{
     new Cage<Sheep> {SomeAnimal=new Sheep()},
     new Cage<Lion> {SomeAnimal=new Lion()},
};

如果您尝试从ICage的声明中删除out,您将看到差异。

public interface IAnimal {
}
public class Animal : IAnimal {
}
public interface ICage {
     IAnimal SomeAnimal {get;}
}
public class Cage : ICage{
     public Animal SomeAnimal { get; set; }
}
public class AnotherAnimal : IAnimal {
}
Cage c = new Cage();
ICage ic = (ICage)c;
ic.Animal = new AnotherAnimal();

这将是无效的,因为AnotherAnimal实现了IAnimal,但它不是Animal

编辑

只有在接口中定义了setter的情况下,以上内容才有意义。因为没有,所以这里的正确答案是,在C#中无法实现所需的功能;这是语言中未包含的功能。