协方差反演仿制药接口 - 为什么这不起作用?

时间:2015-12-16 12:16:20

标签: c# generics interface covariance contravariance

提前谢谢你。这是我的代码:

public class ApplicationUser : IdentityUser
{
    public ApplicationUser()
    {

    }
}

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

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

为什么这不起作用?

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

由于ApplicationUser从UserManager继承IdentityUser和AppUserManager,为什么组合泛型不被接受?谢谢!

2 个答案:

答案 0 :(得分:4)

不支持类的泛型类型参数的逆变和协方差。

简化您的问题:

// Compiler error!
UserManager<IdentityUser> userManager = new AppUserManager();
  • AppUserManager继承UserManager<ApplicationUser>
  • 因此,您尝试在UserManager<ApplicationUser>引用上设置UserManager<IdentityUser>派生的引用。这就是问题!他们是不同的类型。

OP说......

  

这基本上意味着我不能使用具体的课程和他们的   界面中的泛型并期望它们由它们实现   儿?

接口支持差异。因此,您可以按如下方式设计界面:

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

...一旦您实现了此接口,您的实现将声明具体TManager类型的属性。

答案 1 :(得分:3)

马蒂亚斯的回答很好;我以为我会添加更多的上下文。让我们再次简化您的示例:

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

现在的问题是&#34;为什么这种转换是非法的?&#34;

Cage<Animal> cage = new SpecialTigerCage();

现在应该很清楚为什么这是非法的。 你可以将长颈鹿放入可以容纳动物的笼子里,但是如果你把长颈鹿放进一个特殊的虎笼里,长颈鹿就不会对此感到高兴。

类型系统无法证明您不会将长颈鹿放入该虎笼,因此不允许转换。

正如其他人所指出的那样,C#支持在接口和代理上进行这种协变转换,可以证明你不会将长颈鹿放入虎笼。例如IEnumerable<T>是协变的。在需要一系列动物的情况下,可以使用一系列老虎,因为IEnumerable<T>可证明没有方法可以将长颈鹿插入序列中。

相关问题