c#泛型接口协方差

本文关键字:方差 泛型接口 | 更新日期: 2023-09-27 18:05:26

我不知道这里发生了什么,但我得到一个编译器错误使用以下代码:

namespace SO
{
    interface IUser<PostType>
    {
        PostType Post { get; set; }
    }
    interface IPost<UserType>
    {
        UserType User { get; set; }
    }
    class User : IUser<Post>
    {
        //Implementation
    }
    class Post : IPost<User>
    {
        //Implementation
    }
    class SomeOtherClass
    {
        // Compiler Error: Cannot implicitly convert type 'SO.User' to
        // 'SO.IUser<SO.IPost<SO.User>>'. An explicit conversion exists 
        // (are you missing a cast?)
        IUser<IPost<User>> user = new User();
        //Works Fine
        IUser<Post> user = new User();
    }
}

为什么我得到一个错误,如果PostIPost<User>的一个亚型?我知道在这种情况下,我可以使用User而不是IUser<IPost<User>>,但我想知道为什么这不起作用。

c#泛型接口协方差

我将用一个简单的例子来解释它。假设您还有一个实现IPost<User>的类:

class PicturePost : IPost<User>
{
    // Implementation
}

那么这段代码将无法编译:

    IUser<Post> user = new User();
    user.Post = new PicturePost();

因为user.Post是与PicturePost不兼容的具体类Post(它们是兄弟)。

然后想象你的问题中的那一行被成功编译:

    // C# compiler is so kind today and it compiled this.
    IUser<IPost<User>> user = new User();

由于user.Post现在将是IPost<User>类型,您可能会编写这样的行:

    IUser<IPost<User>> user = new User();
    user.Post = new PicturePost();

它们可以完美地编译,但是第二行会失败,出现运行时错误!这是因为user.Post的实际类型是Post,而不是IPostPicturePost

因此,为了实现类型安全,c#编译器禁止在有可能编写此类代码时进行编译。为了确保您不会编写这样的代码,Post属性应该是只读的:

interface IUser<PostType>
{
    PostType Post { get; } // No setter, this is readonly.
}

现在你将不能编写邪恶的代码,Post的所有用法都将是类型安全的,就它的接口而言,因为你只需要获取它,然后完美地分配给它接口的变量。

但是这还不够,要告诉编译器你的接口是轻量级的,你需要显式地指定你的类型参数只有out(你可以使用它,但你不能传递它into)。因此,有了下面的接口实现(注意out关键字),您的代码将编译为:

interface IUser<out PostType>
{
    PostType Post { get; } // No setter, this is readonly.
}
    // Both lines compile!
    IUser<IPost<User>> user = new User();
    IUser<Post> user1 = new User();

希望我保持它的简单,并没有错过重点的同时:)

你必须让你的界面协变:

interface IUser<out PostType>
{
    PostType Post { get; }
}
interface IPost<out UserType>
{
    UserType User { get;  }
}

看到http://msdn.microsoft.com/en-gb/library/ee207183.aspxhttp://msdn.microsoft.com/en-gb/library/dd799517.aspx