关于值类型装箱的困惑

3
在以下代码中...
 int i=5;  
 object o = 5;
 Console.WriteLine(o); //prints 5

我有三个问题:

1) 变量 o 中的数字 5 比变量 i 中的数字 5 多了哪些额外/有用的功能?

2) 如果某段代码需要一个值类型,我们可以直接传递 int 类型的变量 i,但如果它需要一个引用类型,那么它可能并不关心 o 中装箱的数字 5。那么在什么情况下会在代码中显式使用装箱转换?

3) 为什么 Console.WriteLine(o) 输出的是数字 5 而不是 System.Object?

4个回答

5
变量o中的数字5具有哪些变量i所代表的数字5没有的额外/有用功能?
很少有情况需要对某些东西进行装箱,但偶尔必须这样做。在早期版本的.NET中,装箱经常是必要的,因为一些方法只能使用对象(例如ArrayList的方法)。现在有了泛型,这个问题已经不那么严重了,所以新代码中的装箱发生得更少。
如果某些代码期望值类型,那么我们只需传递int i,但如果它期望引用类型,则可能根本不关心o中装箱的数字5。那么什么时候会在代码中明确使用装箱转换呢?
实际上,装箱通常会自动发生。如果您想向代码读者明确说明正在进行装箱,那么可以显式地对变量进行装箱。如果性能可能成为问题,这可能是相关的。
为什么Console.WriteLine(o)打印出5而不是System.Object?
因为ToString是object上的虚拟方法,这意味着被调用的实现取决于运行时类型,而不是静态类型。由于int使用其自己的实现覆盖了ToString,因此调用的是int.ToString,而不是object提供的默认实现。
object o = 5;
Console.WriteLine(o.GetType());  // outputs System.Int32, not System.Object

0

附加功能:该对象是一个完整的对象。您可以调用其方法并像使用任何其他对象一样使用它:

System.Console.WriteLine("type: {0}", o.GetType());
System.Console.WriteLine("hash code: {0}", o.GetHashCode());

int变量是值类型,而不是对象。

XXX:这是不正确的;请参见评论。我认为你可能使用两者之间的区别在于object o = 5是可空的(您可以设置o = null),而值类型不是 - 如果int i = 5,那么i始终是一个整数。

显式装箱:正如你所说,装箱版本用于将编码操作对象作为对象而不是特定的整数。这就是使非类型安全的通用数据结构成为可能的原因。现在有了类型安全的通用数据结构,您不太可能进行大量的强制转换和装箱/拆箱。

为什么是“5”:因为对象知道如何使用ToString()打印自己。


这有点误导人。您可以在 Int32 类型的变量上调用 GetType() 和 GetHasCode() 等方法。这与值类型是否被装箱无关。 - KeithMahoney
@KeithMahoney 您是正确的:我错了。我查阅了C# 3.0语言规范,类型系统非常统一。核心区别在于值类型和引用类型 - 它们涉及对象与其数据之间的关系。 - Jeremy W. Sherman

0
变量 o 中的数字 5 获得了哪些额外/有用的功能,而变量 i 中表示的数字 5 没有?除了可以将装箱值类型传递给需要它的代码之外,没有获得任何其他功能。
那么,什么时候会在代码中显式使用装箱转换呢?我无法立即想到一个场景,需要将 int 显式装箱为 object,因为总是存在隐式转换(尽管如果需要显式转换,我也不会感到惊讶)。
为什么 Console.WriteLine(o) 输出的是 5 而不是 System.Object 呢?
它在传递的对象上调用 ToString。实际上,它首先尝试将对象转换为 IFormattable,如果成功(在 int 的情况下它会成功),则调用定义在该接口中的 ToString 重载方法。这将返回 "5"。

0

1) 单独使用它没有太大的意义。但是想象一下,你希望以通用的方式存储某些东西,而你不知道那个东西是一个值还是一个对象。通过装箱,你可以将值转换为对象,然后将所有东西都视为对象处理。如果没有它,你需要一个特殊情况才能保存一个值或一个对象。(这在容器(如列表)中最有用,允许您混合像5这样的值和对像(如FileStream)的引用)。

2) 装箱转换通常只会隐式发生,除了演示装箱的示例代码。

3) WriteLine 代码可能调用虚拟 Object.ToString() 方法。如果它调用此方法的对象的类没有覆盖 ToString,则它将调用基类(object)实现,但大多数类型(包括 System.Int,尽管 int 是值类型,但仍从 System.Object 派生)覆盖此方法以提供更有用的上下文特定结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接