Contravariance和Entity Framework 4.0:如何将EntityCollection指定为IEnumerable?

Dun*_*yne 6 c# covariance

我已经指定了几个接口,我使用Entity Framework 4实现了实体.我能想到的最简单的演示代码是:

public class ConcreteContainer : IContainer
{
    public EntityCollection<ConcreteChild> Children { get; set; }           
}
public class ConcreteChild : IChild
{
}
public interface IContainer
{
    IEnumerable<IChild> Children { get; set; }
}
public interface IChild
{        
}
Run Code Online (Sandbox Code Playgroud)

我从上面收到以下编译器错误:

'Demo.ConcreteContainer'没有实现接口成员'Demo.IContainer.Children'.'Demo.ConcreteContainer.Children'无法实现'Demo.IContainer.Children',因为它没有匹配的返回类型'System.Collections.Generic.IEnumerable'

我目前的理解是,这是因为IEnumerable(由EntityCollection实现)是协变的,但可能不是逆变的:

此类型参数是协变的.也就是说,您可以使用指定的类型或更多派生的类型.有关协方差和逆变的更多信息,请参阅泛型中的协方差和逆变.

我是否正确,如果是这样,有什么方法可以实现我的目标,IContainer纯粹根据其他接口而不是使用具体类来指定接口?

或者,我是否误解了一些更基本的东西?

Jon*_*eet 5

.NET 4中的泛型差异在这里无关紧要.接口的实现必须在类型方面完全匹配接口签名.

例如,take ICloneable,看起来像这样:

public interface ICloneable
{
    object Clone();
}
Run Code Online (Sandbox Code Playgroud)

能够像这样实现它会很好:

public class Banana : ICloneable
{
    public Banana Clone() // Fails: this doesn't implement the interface
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

...但.NET不允许这样做.您有时可以使用显式接口实现来解决此问题,如下所示:

public class Banana : ICloneable
{
    public Banana Clone()
    {
        ...
    }

    object ICloneable.Clone()
    {
        return Clone(); // Delegate to the more strongly-typed method
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,在你的情况下,你不能这样做.请考虑以下代码,如果ConcreteContainer考虑实现,则该代码有效IContainer:

IContainer foo = new ConcreteContainer();
foo.Children = new List<IChild>();
Run Code Online (Sandbox Code Playgroud)

现在你的属性设置器实际上只是声明可以使用EntityCollection<ConcreteChild>,所以它显然不能用于任何 IEnumerable<IChild> - 违反接口.