我不确定这里发生了什么,但我在使用以下代码时遇到了编译器错误:
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();
}
}
如果 Post
为什么我会收到错误消息是 IPost<User>
的子类型?我知道在这种情况下我可以使用 User
而不是 IUser<IPost<User>>
,但我想知道为什么这不起作用。
最佳答案
我会尝试用简单的例子来解释它。假设你还有一个实现 IPost<User>
的类:
class PicturePost : IPost<User>
{
// Implementation
}
那么这段代码将无法编译:
IUser<Post> user = new User();
user.Post = new PicturePost();
因为 user.Post
属于具体类Post
这与 PicturePost
不兼容(他们是 sibling )。
然后想象一下您问题中的那一行已成功编译:
// 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
不是IPost
或 PicturePost
.
所以,为了实现类型安全,C#编译器如果有可能写出这样的代码,就会禁止编译。为了保证你不会写出这样的代码,Post
属性应该是只读的:
interface IUser<PostType>
{
PostType Post { get; } // No setter, this is readonly.
}
现在你将无法编写恶意代码,Post
的所有用法就其接口(interface)而言将是类型安全的,因为您可以获取它,而不是完美地分配给其接口(interface)的变量。
但这还不够,要告诉编译器你的接口(interface)在light side,你需要显式指定你的类型参数只是out(你可以使用它,但你不能传递它进入)。因此,具有以下接口(interface)实现(注意 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();
希望我保持简单并且同时没有错过重点:)
关于C# 泛型接口(interface)协变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15596005/