2.toString() 会发生装箱吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2.toString() 会发生装箱吗?相关的知识,希望对你有一定的参考价值。

最近被问道了这么问题,我当时回答是会的,因为.toString()会把值类型2转换成引用类型,所以会发生装箱。


后来总觉有些不妥当,所以查阅一些资料并参考网络上的讨论:


拆箱装箱的官方解释

Boxing is the process of converting a value type to the type object or to any interface type implemented by this value type. When the CLR boxes a value type, it wraps the value inside a System.Object and stores it on the managed heap. Unboxing extracts the value type from the object. Boxing is implicit; unboxing is explicit. The concept of boxing and unboxing underlies the C# unified view of the type system in which a value of any type can be treated as an object.


装箱用于在托管内存中存储值类型。 装箱是是值类型到 object 类型或到此值类型所实现的任何接口类型的隐式转换。 对值类型装箱会在堆中分配一个对象实例,并将该值复制到新的对象中。


下面是官方的几个拆箱/装箱的例子:

eg1:
int i = 123;
object o = i;//隐式装箱

eg2:
String.Concat("Answer", 42, true) //42和true都会发生装箱

eg3:
List<object> mixedList = new List<object>();
mixedList.Add("First Group:");
for (int j = 1; j < 5; j++)
{
    mixedList.Add(j);//在添加时,j先装箱
}
var sum = 0;for (var j = 1; j < 5; j++)
{
    //下面的一行会发生编译错误: 
    //Operator ‘*‘ cannot be applied to operands of type ‘object‘ and ‘object‘. 
  //sum += mixedList[j] * mixedList[j]);
  
  //下面经过拆箱就不会出现上面的编译错误.
  sum += (int)mixedList[j] * (int)mixedList[j];
}

Note: 

相对于简单的赋值而言,装箱和取消装箱过程需要进行大量的计算。 对值类型进行装箱时,必须分配并构造一个新对象。 取消装箱所需的强制转换也需要进行大量的计算,只是程度较轻。

更多性能的了解:https://msdn.microsoft.com/zh-cn/library/ms173196.aspx


再引入图片来在说明内存中的变化:

int i = 123;
object o = i;//隐式装箱

技术分享


int i = 123;      // a value type
object o = i;     // boxing
int j = (int)o;   // unboxing

技术分享


看值类型有没有进行拆箱,就看他有没有装换成Object或者值类型所继承的接口类型...

Int.ToString 此方法中,值类型转换成ValueType类型,不满足装箱的条件(可以查看下面IL代码),可以判定Int.ToString是没有装箱的。


.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 代码大小       45 (0x2d)
  .maxstack  3
  .locals init ([0] int32 v, [1] object o)
  IL_0000:  nop
  IL_0001:  ldc.i4.5
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  box        [mscorlib]System.Int32
  IL_0009:  stloc.1
  IL_000a:  ldloca.s   v
  IL_000c:  call       instance string [mscorlib]System.Int32::ToString()
  IL_0011:  ldstr      ","
  IL_0016:  ldloc.1
  IL_0017:  unbox.any  [mscorlib]System.Int32
  IL_001c:  box        [mscorlib]System.Int32
  IL_0021:  call       string [mscorlib]System.String::Concat(object,
                                                              object,
                                                              object)
  IL_0026:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_002b:  nop
  IL_002c:  ret
} // end of method Program::Main


了解了上面的信息之后以后就知道下面建议用哪一个了吧:

int num = 3;
//用下面的哪个呢?请思考
string numStr = string.Format("{0}", num);
string numStr = string.Format("{0}", num.ToString());


参考:

https://msdn.microsoft.com/en-us/library/yz2be5wk.aspx

http://www.cnblogs.com/DebugLZQ/archive/2012/09/02/2667835.html

http://q.cnblogs.com/q/44027

http://bbs.csdn.net/topics/360191652

本文出自 “lybing” 博客,请务必保留此出处http://lybing.blog.51cto.com/3286625/1790605

以上是关于2.toString() 会发生装箱吗?的主要内容,如果未能解决你的问题,请参考以下文章

转 C# 装箱和拆箱[整理]

对值类型调用方法会导致 .NET 中的装箱吗?

CLR类型设计之泛型

C#---装箱和拆箱

C#装箱与拆箱总结

使用反射设置 C# 结构/类字段时是不是可以避免装箱?