I have specified a couple of interfaces, which I am implementing as entities using Entity Framework 4. The simplest demonstration code I can come up with is:
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
{
}
I receive the following compiler error from the above:
‘Demo.ConcreteContainer’ does
not implement interface member
‘Demo.IContainer.Children’.
‘Demo.ConcreteContainer.Children’
cannot implement
‘Demo.IContainer.Children’
because it does not have the matching
return type of
‘System.Collections.Generic.IEnumerable’
My current understanding is that this is because IEnumerable (which is implemented by EntityCollection) is covariant but presumably not contravariant:
This type parameter is covariant. That is, you can use
either the type you specified or any type that is more
derived. For more information about covariance and contravariance,
see Covariance and Contravariance in Generics.
Am I correct, & if so, is there any way I can achieve my goal of specifying the IContainer interface purely in terms of other interfaces rather than using concrete classes?
Or, am I misunderstanding something more fundamental?
The generic variance in .NET 4 is irrelevant here. The implementation of an interface has to match the interface signature exactly in terms of types.
For example, take
ICloneable, which looks like this:It would be nice to be able to implement it like this:
… but .NET doesn’t allow this. You can sometimes use explicit interface implementation work around this, like so:
However, in your case you can’t ever do that. Consider the following code, which would be valid if
ConcreteContainerwas considered to implementIContainer:Now your property setter is actually only declared to work with
EntityCollection<ConcreteChild>, so it clearly can’t work with anyIEnumerable<IChild>– in violation of the interface.