拳击和拆箱:什么时候出现?

时间:2009-12-22 21:02:41

标签: c# object boxing

所以我明白拳击和拆箱是什么。什么时候出现在现实世界的代码中,或者在什么样的例子中出现问题?我无法想象做这样的例子:

int i = 123;
object o = i;           // Boxing
int j = (int)o;     // Unboxing

......但这几乎肯定是极度过于简单,我甚至可能在以前不知情的情况下完成了装箱/拆箱。

7 个答案:

答案 0 :(得分:32)

现在, 现在,例如,我们可以使用:

List<int> x = new List<int>();
x.Add(10);
int y = x[0];

根本不需要拳击或拆箱。

以前,我们已经:

ArrayList x = new ArrayList();
x.Add(10); // Boxing
int y = (int) x[0]; // Unboxing

这至少是最常见的拳击和拆箱经验。

如果没有泛型参与,我想我可能会说反思是我参与过的项目中拳击的最常见原因。反射API总是使用“对象”来表示方法的返回值 - 因为他们没有其他方法可以知道要使用什么。

如果您不了解它,可能会引起您注意的另一个原因是您是否使用实现接口的值类型,并将该值传递给另一个以接口类型作为参数的方法。同样,泛型使这不是一个问题,但如果你不了解它,它可能是一个令人讨厌的惊喜。

答案 1 :(得分:8)

拳击(根据我的经验)通常发生在这些情况下:

  • 将值类型传递给接受类型为Object的参数的方法。
  • 将值类型添加到非泛型集合(如ArrayList)。

其他时候你可以看到装箱和拆箱是因为.NET框架的反射API大量使用Object时使用反射。

答案 2 :(得分:4)

当值类型(如struct,int,long)传递到接受引用类型的某处时(例如object),就会发生装箱/取消装箱。

当您显式创建一个方法,该方法接受将传递值类型的object类型的参数时,会发生这种情况。当您使用较旧的非泛型集合来存储值类型(通常是基元)时,它也会出现。

当您使用String.Format()并向其传递基元时,您还会看到拳击事件发生。这是因为String.Format()接受了一个params对象[] - 这会导致在调用中装入其他参数。

使用反射调用方法也可能导致装箱/取消装箱,因为反射API别无选择,只能返回object,因为在编译时不知道真实类型(并且反射API不能通用)

较新的通用集合不会导致装箱/取消装箱,因此出于这个原因(例如ArrayList,Hashtable等)优于旧集合。更不用说它们是类型安全的。

您可以通过更改接受通用对象的方法来避免拳击问题。例如:

public void string Decorate( object a ) // passing a value type results in boxing
{
   return a.ToString() + " Some other value";
}

VS

public void string Decorate<T>( T a )
{
   return a.ToString() + " some other value";
}

答案 3 :(得分:3)

这是一个非常讨厌的人:)

SqlCommand cmd = <a command that returns a scalar value stored as int>;

// This code works very well.
int result = (int)cmd.ExecuteScalar();

// This code will throw an exception.
uint result = (uint)cmd.ExecuteScalar();

第二次执行失败,因为它试图将Int32解包到UInt32中,这是不可能的。所以你必须首先拆箱而不是投石。

uint result = (uint)(int)cmd.ExecuteScalar();

答案 4 :(得分:1)

拳击和拆箱实际上是从值类型转移到引用类型。所以,把它想象成从堆栈转移到堆然后再回来。

确实存在相关的情况。在2.0框架中包含泛型可以减少许多常见的拳击案例。

答案 5 :(得分:1)

当人们不知道其含义是什么时,它总是发生,只是不在乎,或者有时人们会忍不住接受拳击作为较小的等级。

当您访问值类型属性时,强类型数据行将一直打开/取消装箱。 此外,使用值类型作为接口引用也会将其打包。或者从值类型的实例方法获取委托。 (委托的目标是Object类型)

答案 6 :(得分:0)

自从使用带有C#2.0的泛型(Visual Studio 2005)的强类型列表和词典出现以来,我认为保持装箱/拆箱的重要性已被惊人地最小化。添加到那些可空类型(int?等)并使用空合并运算符(??),它实际上应该不是很关注,并且很可能在任何代码中都看不到它这不是1.1框架或更早。