c#4.0:int 对象的真正子类型?协方差、可枚举和值类型
我想知道为什么 IEnumerable
不能分配给 IEnumerable
- 子类型关系和协变的东西与引用类型
- int 一起工作似乎是
的正确子类型object
然而,这两个功能的组合不起作用...
class A
{
}
class B : A
{
}
class Program
{
static void Main(string[] args)
{
bool b;
b = typeof(IEnumerable<A>).IsAssignableFrom(typeof(List<B>));
Console.WriteLine("ienumerable of ref types is covariant: " + b); //true
b = typeof(IEnumerable<object>).IsAssignableFrom(typeof(List<int>));
Console.WriteLine("ienumerable of value tpyes is covariant: " + b); //false
b = typeof(object).IsAssignableFrom(typeof(int));
Console.WriteLine("int is a subtype of object: " + b); //true
}
}
感谢您的帮助! 塞巴斯蒂安
I wonder why IEnumerable<int>
can't be assigned to a IEnumerable<object>
. After all IEnumerable
is one of the few interfaces that supports covariance...
- The subtype relation and covariance stuff works with reference types
int
seems to be a proper subtype ofobject
The combination of both features doesn't work however...
class A
{
}
class B : A
{
}
class Program
{
static void Main(string[] args)
{
bool b;
b = typeof(IEnumerable<A>).IsAssignableFrom(typeof(List<B>));
Console.WriteLine("ienumerable of ref types is covariant: " + b); //true
b = typeof(IEnumerable<object>).IsAssignableFrom(typeof(List<int>));
Console.WriteLine("ienumerable of value tpyes is covariant: " + b); //false
b = typeof(object).IsAssignableFrom(typeof(int));
Console.WriteLine("int is a subtype of object: " + b); //true
}
}
thanks for your help!
sebastian
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在装箱之前,值类型不是对象的 LSP 子类型。
方差不适用于值类型。完全没有。
证明
int
不是object
的正确子类型(LSP 意义上的子类型):有效:
无效(违反可替代性):
返回true:
返回 false(违反可替代性):
当然,问题的主题(界面差异)是第三个演示。
Value types aren't LSP-subtypes of object until they're boxed.
Variance doesn't work with value types. At all.
Demonstration that
int
is not a proper subtype (subtype in the LSP sense) ofobject
:Works:
Does not work (substitutability violated):
Returns true:
Returns false (substitutability violated):
Of course, the topic of the question (interface variance) is a third demonstration.
问题在于
object
是引用类型,而不是值类型。可以将int
分配给object
类型的变量的唯一原因是装箱。为了将
List
分配给IEnumerable
The problem is that
object
is a reference type, not a value type. The only reason you can assign anint
to a variable of typeobject
is boxing.In order to assign
List<int>
toIEnumerable<object>
you'd have to box each element of the list. You can't do that just by assigning the reference to the list and calling it a different type.简单化的答案是,这只是 C# 和 CLR 中实现方差的方式中的怪癖之一。
来自“泛型中的协变和逆变”:
The simplistic answer is that this is just one of the quirks in the way that variance is implemented in C# and the CLR.
From "Covariance and Contravariance in Generics":
.net 中的每个值类型都有一个相应的(“装箱的”)对象类型。非装箱值类型实际上位于对象类型层次结构之外,但编译器将执行从值类型到装箱类类型的扩展。有一个“类” Boxed会很有帮助。它将支持与 T 之间的扩展转换,但它将是一个类类型。在内部,我认为这就是编译器隐式执行的操作,但我不知道有什么方法可以显式执行此操作。对于像“整数”这样的任何特定类型,定义一个表现得像 Boxed的类是没有困难的。应该,但我不知道以通用方式做这样的事情有什么方法。
Every value type in .net has a corresponding ("boxed") object type. Non-boxed value types are effectively outside the object type hierarchy, but the compiler will perform a widening from the value type to the boxed class type. It would be helpful to have a "class" Boxed<T> which would support a widening conversions to and from T, but which would be a class type. Internally, I think that's what the compiler's doing implicitly, but I don't know any way to do it explicitly. For any particular type like "integer", there would be no difficulty defining a class which would behave as a Boxed<Integer> should, but I don't know any way of doing such a thing in generic fashion.