.NET 4.0 协方差
回应另一个问题 我已尝试执行以下操作。我认为我没有正确解释这个问题,但我确实想知道以下内容是否可能以某种方式(我的尝试失败了),如果不是为什么不:
public class MyBaseClass { }
public class MyClass : MyBaseClass { }
public class B<T> { }
public class A<T> : B<T> { }
static void Main(string[] args)
{
// Does not compile
B<MyBaseClass> myVar = new A<MyClass>();
}
我认为这可能可以使用带有协变类型参数的通用接口来工作:
interface IB<out T> { }
public class B<T> : IB<T> { }
但我错了,这也不起作用。
编辑
正如 SLAks 所指出的“接口是协变的;类不是。 (感谢 SLAks)。所以现在我的问题是为什么?设计背后的想法是什么(我认为是埃里克·利珀特(Eric Lippert)的设计)是不可能的、不可取的还是它在“也许有一天”的清单上?
In response to another question I have tried to do the following. I don't think I interpreted that question correctly, but I do wonder if the below is possible somehow (my attempts have failed) and if not why not:
public class MyBaseClass { }
public class MyClass : MyBaseClass { }
public class B<T> { }
public class A<T> : B<T> { }
static void Main(string[] args)
{
// Does not compile
B<MyBaseClass> myVar = new A<MyClass>();
}
I thought this might be made to work using a generic interface with a covariant type parameter:
interface IB<out T> { }
public class B<T> : IB<T> { }
but I was wrong about that, that does not work either.
EDIT
As SLaks has pointed out 'Interfaces are covariant; classes are not.' (thanks SLaks). So now my question is why? What was the thinking behind the design (one for Eric Lippert I think) is it not possible, undesirable or is it on a 'maybe one day' list?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你们有很好的伙伴;几周前,乔恩·斯基特和比尔·瓦格纳问了我同样的问题。我一直在写一篇关于它的博客文章,但简单地说:
要求明确答案的合适人选是微软剑桥研究院的安德鲁·肯尼迪,他最初设计并实现了大部分通用和方差逻辑。然而,我可以大胆地猜测一下为什么我们决定避免通用类上的差异。
简短的版本是:T 的安全协变要求 T 上的操作是“只读”的。 T 的逆变要求 T 上的操作是“只写”的。您有一个类
C
,您希望将其作为 T 的变体。假设 `C 有一个 T 类型的字段:您希望该字段只读 或只能写?因为那些都是你的选择!在什么情况下,拥有一个可写但不可读取的字段甚至有点用处?不多。在什么情况下有一个只能读但不能写的字段有用? 仅当字段标记为只读时。
简而言之,逆变泛型类几乎从来没有用处,因为您无法从中读取任何泛型数据,而协变类通常仅在该类是不可变数据类型时才有用。
我是不可变数据类型的忠实粉丝,我认为能够创建协变不可变堆栈而无需涉及接口将是一个很棒的功能。但协变泛型持久不可变函数数据结构在 C# 中还不完全是主流,当泛型被添加到 CLR 时,它们也肯定不是主流。此外,除了只读字段之外,我们没有其他支持基础设施来在 C# 或 CLR 中表达“这是一种不可变数据类型”的概念;如果我们要为不可变类创建协变类类型,那么最好做很多支持不可变类的功能,而不仅仅是这个晦涩难懂的功能。
所以我可以看出这个功能为何没有在 CLR 2.0 / C# 2.0 中脱颖而出。如果我们今天再次设计它,当函数式编程更加流行时,也许会这样。但我们短期内没有这样做的计划。
我将在接下来的几个月内写一篇博客文章,给出更详细的答案。
You are in good company; Jon Skeet and Bill Wagner asked me that same question a couple weeks ago. I have been working up a blog post on it, but briefly:
The right person to ask for a definitive answer is Andrew Kennedy at Microsoft Research Cambridge, who designed and implemented much of the generic and variance logic originally. However, I can hazard an educated guess as to why we decided to eschew variance on generic classes.
The short version is: Safe covariance of T requires that operations on T be "read only". Contravariance of T requires that operations on T be "write only". You have a class
C<T>
which you wish to be variant in T. Suppose `C has a field of type T: would you like to have that field be only readable or only writable? Because those are your choices!Under what circumstances is it even vaguely useful to have a field that can be written to but not read? Not many. Under what circumstances is it useful to have a field that can be read but not written to? Only if the field is marked readonly.
In short, contravariant generic classes are almost never useful because you can't read any generic data from them, and covariant classes are mostly only useful if the class is an immutable data type.
I am a big fan of immutable data types and I think it would be a great feature to be able to make a covariant immutable stack without having to get an interface involved. But covariant generic persistent immutable functional data structures are not exactly mainstream in C# yet, and they certainly were not when generics were added to the CLR. Moreover, we have no supporting infrastructure other than readonly fields to express the notion "this is an immutable data type" in C# or the CLR; if we were to do covariant class types for immutable classes, it would be nice to do lots of features that support immutable classes, not just this obscure one.
So I can see how this feature did not make the cut in CLR 2.0 / C# 2.0. If we were designing it again today, when functional-style programming is somewhat more popular, maybe it would. But we have no plans to do so any time soon.
I'll write a blog post in the next few months giving a more detailed answer.
接口是协变的;类不是。
A
可以转换为IB
。Interfaces are covariant; classes are not.
A<MyClass>
can be converted toIB<MyBaseClass>
.直接类到类的转换不起作用,但如果您使用 IB 接口作为变量类型,那么就可以了。根据此 MSDN 协方差常见问题解答博客帖子和关于协变和逆变的 MSDN 页面,变体类型参数仅限于通用接口和通用委托类型。
The direct class to class conversion doesn't work, but if you use your IB interface for the variable type you're good to go. As per this MSDN covariance FAQ blog post and the MSDN page on Covariance and Contravariance, variant type parameters are restricted to generic interface and generic delegate types.