我不确定这里发生了什么,但我使用以下代码收到编译错误:
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>>
,但我想知道为什么这不起作用。
答案 0 :(得分:12)
我将尝试使用简单的示例来解释它。假设您还有一个实现IPost<User>
的类:
class PicturePost : IPost<User>
{
// Implementation
}
然后这段代码将无法编译:
IUser<Post> user = new User();
user.Post = new PicturePost();
因为user.Post
具有与Post
不兼容的具体类PicturePost
(他们是兄弟姐妹)。
然后想象你问题中的那一行是否成功编译:
// 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 (你可以使用它,但你不能通过它进入)。因此,在接口(通知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();
希望我保持简单并且不会同时忽略这一点:)
答案 1 :(得分:0)
嗯,你必须使你的界面协变:
interface IUser<out PostType>
{
PostType Post { get; }
}
interface IPost<out UserType>
{
UserType User { get; }
}
请参阅 http://msdn.microsoft.com/en-gb/library/ee207183.aspx http://msdn.microsoft.com/en-gb/library/dd799517.aspx