C#泛型接口协方差 [英] C# Generics Interface Covariance

查看:85
本文介绍了C#泛型接口协方差的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定这是怎么回事,但是使用以下代码遇到编译器错误:

I'm not sure what's going on here but I'm getting a compiler error using the following code:

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();
    }
}

如果<$ c $,为什么会出错c> Post 是 IPost< User> 的子类型吗?我知道在这种情况下,我可以只使用 User 代替 IUser< IPost< User>> ,但是我想要知道为什么这行不通。

Why am I getting an error if Post is a subtype of IPost<User>? I know in this case I could just use User instead of IUser<IPost<User>>, but I want to know why this doesn't work.

推荐答案

我将尝试使用简单的示例进行解释。假设您还有一个实现 IPost< User> 的类:

I will try to explain it using simple example. Suppose you have one more class implementing IPost<User>:

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

然后此代码将无法编译:

Then this code will not compile:

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

因为 user.Post 是具体类 Post PicturePost (他们是兄弟姐妹)不兼容。

Because user.Post is of concrete class Post which is not compatible with PicturePost (they are siblings).

然后想象您问题中的行已成功编译:

Then imagine that line from your question was successfully compiled:

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

由于 user.Post 现在将是键入 IPost< User> ,您可能会编写以下代码行:

Since user.Post now will be of type IPost<User> you potentially will code such lines:

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

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

And they will compile perfectly, but second line will fail with run-time error! This is because actual type of user.Post is Post not IPost or PicturePost.

因此,为了实现类型安全,C#编译器禁止编译,如果存在编写此类代码的机会。为了确保您不会编写此类代码, Post 属性应为只读:

So, in order to achieve type-safety, C# compiler prohibits compiling if there is a chance of such code to be written. In order to ensure that you will not write such code, Post property should be read-only:

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

现在您将无法编写邪恶的代码,并且 Post 就其接口而言是类型安全的,因为您可以获取它,而不是为其接口变量完美分配。

Now you will not be able to write evil code, and all usages of Post will be type-safe in respect of its interface, since you can just get it, and than perfectly assign to variable of its interface.

但这还不够,要告诉编译器您的接口比较简单,您需要明确指定类型参数仅为 out (您可以使用它,但不能将其传递给)。因此,使用下面的接口实现(注意 out 关键字),您的代码将编译:

But this is not enough, to tell compiler that your interface on the light side, you need to explicitly specify that your type parameter is only out (you can use it, but you cannot to pass it into). So, having below implementation of interface (notice out keyword), your code will compile:

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();

希望我保持简单,不要同时遗漏要点:)

Hope I kept it simple and did not miss the point at the same time:)

这篇关于C#泛型接口协方差的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆