协变通用参数
我试图理解这一点,但我没有从搜索中得到任何合适的结果。
在 C# 4 中,我可以做
public interface IFoo<out T>
{
}
这与
public interface IFoo<T>
{
}
我所知道的有什么不同,就是 out
使泛型参数协变 (??)。 有人可以举例解释
部分的用法吗?为什么仅适用于接口和委托而不适用于类?
抱歉,如果它是重复的,请关闭它(如果是)。
I'm trying to understand this but I didn't get any appropriate results from searching.
In C# 4, I can do
public interface IFoo<out T>
{
}
How is this different from
public interface IFoo<T>
{
}
All I know is the out
makes the generic parameter covariant (??).
Can someone explain the usage of <out T>
part with an example? And also why is applicable only for interfaces and delegates and not for classes?
Sorry if it's a duplicate and close it as such if it is.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当然。
IEnumerable
是协变的。这意味着您可以这样做:“协变”意味着类型参数的赋值兼容性关系保留在泛型类型中。
Giraffe
与Animal
赋值兼容,因此该关系保留在构造类型中:IEnumerable
与赋值兼容IEnumerable<动物>
。类的问题在于类往往具有可变字段。让我们举个例子。假设我们允许这样做:
好的,现在在继续之前仔细思考这个问题。
C
可以在构造函数之外使用任何方法将字段t
设置为其默认值以外的其他值吗?因为它必须是类型安全的,
C
现在不能有以 T 作为参数的方法; T只能退回。那么谁设置 t,他们从哪里获取设置的值?协变类类型实际上仅在类不可变时才起作用。而且我们没有好的方法在 C# 中创建不可变类。
我希望我们这样做,但我们必须接受我们所获得的 CLR 类型系统。我希望将来我们能够更好地支持不可变类和协变类。
如果您对此功能感兴趣,请考虑阅读我关于我们如何设计和实现该功能的长系列文章。从底部开始:
https://blogs.msdn.microsoft.com /ericlippert/tag/协方差和逆变/
Sure.
IEnumerable<T>
is covariant. That means you can do this:"Covariant" means that the assignment compatibility relationship of the type argument is preserved in the generic type.
Giraffe
is assignment compatible withAnimal
, and therefore that relationship is preserved in the constructed types:IEnumerable<Giraffe>
is assignment compatible withIEnumerable<Animal>
.The problem with classes is that classes tend to have mutable fields. Let's take an example. Suppose we allowed this:
OK, now think this question through carefully before you go on. Can
C<T>
have any method outside of the constructor that sets the fieldt
to something other than its default?Because it must be typesafe,
C<T>
can now have no methods that take a T as an argument; T can only be returned. So who sets t, and where do they get the value they set it from?Covariant class types really only work if the class is immutable. And we don't have a good way to make immutable classes in C#.
I wish we did, but we have to live with the CLR type system that we were given. I hope in the future we can have better support for both immutable classes, and for covariant classes.
If this feature interests you, consider reading my long series on how we designed and implemented the feature. Start from the bottom:
https://blogs.msdn.microsoft.com/ericlippert/tag/covariance-and-contravariance/
如果我们谈论通用方差:
协方差就是从操作返回给调用者的值。
逆变 它是相反的,它与调用者传入的值有关:
据我所知,如果类型参数仅用于输出,则可以使用 out。但是,如果该类型仅用于输入,则可以使用 in。这样很方便,因为编译器无法确定您是否记得哪种形式称为协变,哪种形式称为逆变。如果在声明类型后不显式声明它们,则可以隐式使用相关类型的转换。
类中不存在方差(协方差或逆变),因为即使您有一个仅使用类型参数作为输入(或仅将其用于输出)的类,您
无法指定 in 或 out 修饰符。只有接口和委托可以具有变体类型参数。首先CLR不允许这样做。从概念的角度来看,接口代表了从特定角度查看对象的一种方式,而类则是更多的实际实现类型。
If we're talking about generic variance:
Covariance is all about values being returned from an operation back to the caller.
Contravariance It’s opposite and it's about values being passed into by the caller:
From what I know if a type parameter is only used for output, you can use out. However if the type is only used for input, you can use in. It's the convenience because the compiler cannot be sure if you can remember which form is called covariance and which is called contravariance. If you don't declare them explicitly once the type has been declared, the relevant types of conversion are available implicitly.
There is no variance (either covariance or contravariance) in classes because even if you have a class that only uses the type parameter for input (or only uses it for output), you
can’t specify the in or out modifiers. Only interfaces and delegates can have variant type parameters. Firstly the CLR doesn’t allow it. From the conceptual point of view Interfaces represent a way of looking at an object from a particular perspective, whereas classes are more actual implementation types.
这意味着如果您有以下内容:
那么
IFoo
的实例也是IFoo
的实例。It means that if you have this:
Then an instance of
IFoo<Child>
is also an instance ofIFoo<Parent>
.