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();
}
}
为什么我得到一个错误,如果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
是与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
,而不是IPost
或PicturePost
。
因此,为了实现类型安全,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