Reputation: 755
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!
Upvotes: 0
Views: 176
Reputation: 660032
Matias's answer is good; I thought I'd add a bit more context. Let's again simplify your example:
class Animal {} // IdentityUser
class Tiger : Animal {} // ApplicationUser
class Giraffe : Animal {} // some other kind of user
class Cage<T> where T : Animal {} // UserManager
class SpecialTigerCage : Cage<Tiger> {} // AppUserManager
The question now is "why is this conversion illegal?"
Cage<Animal> cage = new SpecialTigerCage();
It should be obvious now why this is illegal. You can put a giraffe into a cage that can contain animals, but if you put a giraffe into a special tiger cage, the giraffe is not going to be very happy about it.
The type system cannot prove to its satisfaction that you're not going to put a giraffe into that tiger cage, so it disallows the conversion.
As others pointed out, C# does support this sort of covariant conversion on interfaces and delegates, where it can prove that you're not going to put a giraffe into a tiger cage. IEnumerable<T>
for example is covariant. A sequence of tigers may be used where a sequence of animals is needed because IEnumerable<T>
provably has no method that can insert a giraffe into the sequence.
Upvotes: 3
Reputation: 64923
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>
.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.
Upvotes: 4