在IEnumerable <t> </t>的上下文之外使用协方差

时间:2012-12-27 15:46:29

标签: c# inheritance covariance

  

可能重复:
  Does C# support return type covariance?
  Why can’t I implement an Interface this way?

请考虑以下事项:

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”。既然它定义了动物,它比IAnimal更明确,似乎协方差应该照顾我。

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

4 个答案:

答案 0 :(得分:6)

目前在C#中无法实现。

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

最好的解决方法可能是:

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

    IAnimal ICage.SomeAnimal
    {
        get { return SomeAnimal }
    }
}

答案 1 :(得分:2)

引自Eric Lippert,回答我在这里问同样的问题: Why can't I implement an Interface this way?

  

C#不支持返回类型协方差   接口实现或虚拟方法覆盖。看到这个   问题详情:

     

Does C# support return type covariance?

     

C#确实支持接口的通用协方差和逆变   以及用于构造的引用类型和委托类型   从C#4开始输入参数。

     

转换方法时,C#确实支持返回类型协方差   将引用类型返回给返回类型为的委托类型   兼容的参考类型。 (同样它支持参数类型   逆变。)

     

如果这个主题让你感兴趣,我写了很多文章   讨论C#所做和不做的各种版本的差异   支持。参见

     

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/

     

了解详情。

答案 2 :(得分:2)

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#中无法实现所需的功能;它是一种未包含在该语言中的功能。

答案 3 :(得分:2)

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

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()},
};

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