Search code examples
c#genericsinterfacecovariancecontravariance

Covariance Contravariance Generics Interfaces - why doesn't this work?


Thank you in advance. Here is my code:

public class ApplicationUser : IdentityUser
{
    public ApplicationUser()
    {

    }
}

public class AppUserManager : UserManager<ApplicationUser>
{
...
}

public interface IOwinManager
{
    UserManager<IdentityUser> UserManager { get; }
}

Why is this not working?

public class OwinManager : IOwinManager
{        
    public UserManager<IdentityUser> UserManager
    {
        get { return new AppUserManager(); }
    }
}

Since ApplicationUser inherits from IdentityUser and AppUserManager from UserManager, why is the combined generic not accepted? Thanks!


Solution

  • Both contravariance and covariance on generic type parameters for classes isn't supported.

    Simplifying your issue:

    // Compiler error!
    UserManager<IdentityUser> userManager = new AppUserManager();
    
    • AppUserManager inherits UserManager<ApplicationUser>.
    • Thus, you're trying to set an UserManager<ApplicationUser>-derived reference on a UserManager<IdentityUser> reference. This is the problem! They're different types.

    OP said...:

    which, essentially means, I can't use concrete classes and their generics in an interface and expect them to be implemented by their children?

    Interfaces support variance. Thus, you can design your interface as follows:

    public interface IOwinManager<out TUser, out TManager>
        where TUser : IdentityUser 
        where TManager : UserManager<TUser>
    {
        TManager UserManager { get; }
    }
    

    ...and once you've implemented this interface, your implementation will declare a property of the concrete TManager type.