Dusty
Dusty

Reputation: 643

ICollection in interface with another interface as the type

Is it possible to specify an interface as the type for a generic collection property of a different interface and then implement it with a specific class? Here is an example of what I am trying to do:

public interface IMembershipPrincipal
{
    int ID { get; set; }
    string UserName { get; set; }
    ICollection<IEmail> Emails { get; set; }
}

public interface IEmail
{
    string Address { get; set; }
    int UserID { get; set; }
}

and defining the actual classes in another project:

public class User : IMembershipPrincipal
{
    [Key]
    public int ID { get; set; }
    public string UserName { get; set; }
    public virtual ICollection<Email> Emails { get; set; }
}

public class Email : IEmail
{
    [Key]
    public string Address { get; set; }
    public int UserID { get; set; }
}

In the IMembershipPrincipal I only have access to the IEmail definition, but I would like to implement the ICollection using Email instead of IEmail. I am currently getting an error that says:

Error 1 'User' does not implement interface member 'IMembershipPrincipal.Emails'. 'User.Emails' cannot implement 'IMembershipPrincipal.Emails' because it does not have the matching return type of 'System.Collections.Generic.ICollection'.`

How can I change my IMembershipPrincipal definition so that it can be implemented with ICollection<Email>?

Just to be clear, I understand that implementing the virtual collection as ICollection<IEmail> will make the code build, but it destroys my paths in Entity framework so that I can't do something like MyUser.Emails.Where(...).

Upvotes: 2

Views: 692

Answers (1)

CD Waddell
CD Waddell

Reputation: 248

As mentioned by others, covariance keeps you from using the code from your example. You however, can use generic types and constraints to get the desired effect.

public interface IMembershipPrincipal<T> where T:IEmail
{
    int ID { get; set; }
    string UserName { get; set; }
    ICollection<T> Emails { get; set; }
}

public interface IEmail
{
    string Address { get; set; }
    int UserID { get; set; }
}

public class User : IMembershipPrincipal<Email>
{
    [Key]
    public int ID { get; set; }
    public string UserName { get; set; }
    public virtual ICollection<Email> Emails { get; set; }
}

public class Email : IEmail
{
    [Key]
    public string Address { get; set; }
    public int UserID { get; set; }
}

Upvotes: 3

Related Questions