Search code examples
c#inheritanceinterfacebreeze-sharp

Why interface is not implemented: List<string> is ICollection<string>


Consider the C# snippet:

    interface Contract
    {
        ICollection<string> Coll { get; }
    }

    class Implementation : Contract
    {
        public List<string> Coll { get; } //this declaration is mandatory for other reason
    }

Why Implementation does not implement Contract?

List<string> implements ICollection<string>

Real case

    //Entity Framework 
    public partial class ApplicationUser : IdentityUser<Guid>
    {
      ...
      public virtual ICollection<Message> Messages { get; set; }
    }

    //Breeze.Sharp Entity 
    public partial class ApplicationUser : BaseEntity
    {
      ...
      public NavigationSet<Message> Messages
        {
            get { return GetValue<NavigationSet<Message>>(); }
        }
    }

How to find an interface that both classes implement?


Solution

  • An interface is a contract for consumers of your code. In your case that contract states: "there is a member called Coll which is of type ICollection<string>".

    Implementations of your interface therefor have to follow it - that is they have to implement members exactly the same way the contract defines them - this is you need the exact same signature as of the interface.

    Furthermore there´s absoluteley no way for a consumer to determine if or if not the member is of a more deerived type. In fact consumers shouldn´t care for that at all. That´s the point of an interface - to have an abstracttion about your actual implementations. So even if your implementation would work, clients have no way to use it:

    Contract myContrac = new Implementation();
    var list myContract.Coll; 
    

    As the interface states, list now is of type ICollection<string>. There´s no way to call any of List<T>s members, unless you explicitely cast to List<string>, which contradicts the point of abstractions and interfaces. This way you can easily exchange the actual implementation by a newer version for example, without clients need to do anything.

    EDIT: to get an interface for both your classes you can use an explicit interface-implementation:

    interface BaseEntity
    {
        ICollection<Message> { get; }
    }
    //Entity Framework 
    public partial class ApplicationUser : IdentityUser<Guid>
    {
        public virtual ICollection<Message> Messages { get; }
    }
    
    //Breeze.Sharp Entity 
    public partial class ApplicationUser : BaseEntity
    {
        public NavigationSet<Message> Messages
        {
            get { return GetValue<NavigationSet<Message>>(); }
        }
        BaseIntity.ICollection<Message> Messages { get => this.Messages; }
    }