0

I'm trying to create a blog, so each post has some topic and vise versa (a many-to-many relationship). I've created two Interfaces and two Classes, and I want to create database using EF Code First solution. this is my code:

// interfaces

public interface IPost
{
    int id { get; set; }

    string name { get; set; }

    IEnumerable<ITopic> topics { get; set; }
}

public interface ITopic
{
    int id { get; set; }

    string name { get; set; }

    IEnumerable<IPost> posts { get; set; }
}

// classes

public class Post : IPost
{
    public int id { get; set; }

    public string name { get; set; }

    // ... (other properties)

    public virtual ICollection<Topic> topics { get; set; }
}

public class Topic : ITopic
{
    int id { get; set; }

    string name { get; set; }

    // ... (other properties)

    public virtual ICollection<Post> posts { get; set; }
}

But I get the following error:

'Topic' does not implement interface member 'ITopic.posts'. 'Topic.posts' cannot implement 'ITopic.posts' because it does not have the matching return type of 'IEnumerable<IPost>'.

And also, I get the (almost) same error for Post.

I know that ICollection<T> implements IEnumerable<T> interface. and, as you see, Post implements IPost. So, why i get this error? I tried these also (whitin Topic class):

1- public virtual ICollection<IPost> posts { get; set; }

2- public virtual IEnumerable<Post> posts { get; set; } (why this one dose not work?!)

The only code that works is public virtual IEnumerable<IPost> posts { get; set; }, but then I will lose the other propertis of a Post when enumerating topic.posts. worse, I can't create database using EF Code First solution.

Is there any workaround to solve this problem?

  • Simply, `ICollection` is invariant for `T`. In other words, it doesn't allow subtyping of the generic argument. – Chris Pratt Aug 23 '16 at 13:22
  • `ICollection` is an invariant interface, because `T` is used for parameter types as well as for return types. Thatswhy a `ICollection` is a _different_ type (no inheritance or what so ever) than `ICollection`. You could declare both properties (and the one from `ITopic` as `virtual ITopic.ICollection posts {get;set;}` but that would mean to have two separate collections you'd need to synchronize. Don't see a good work around at first glance... maybe having interfaces is not _so_ necessary and you could live with class declarations only? – René Vogt Aug 23 '16 at 13:24
  • why my trying #2 not working?! – Ali Fathi Aug 23 '16 at 13:25
  • It does not work because the compiler thinks this should be the implementation of the interface's `posts` property, but the type does not match. – René Vogt Aug 23 '16 at 13:26
  • so now what shoud i do? trying to get rid of interfaces?! – Ali Fathi Aug 23 '16 at 13:28
  • 1
    Why do you need the Interfaces? In my understanding, you are using the interfaces only one time. If this is correct, the interfaces are totally unnecessary. – Fruchtzwerg Aug 23 '16 at 13:30
  • no, i want to use interfaces within my services and repositories. – Ali Fathi Aug 23 '16 at 13:33
  • But this causes a lot of problems here. As I said above you _could_ declare both properties (by hiding the interface implementation), but then you have the problem that the getters would return two different collection instances (they can't return the _same_ instance because of type mismatch), so there could be some behaviour not expected by consumers of your class. – René Vogt Aug 23 '16 at 13:39

0 Answers0