虽说使用C#很长时间了,对Box的概念一直没有搞清楚。今天抽时间专门研究了一下,有一些发现。
具体对比过程见下,ildasm代码中有注释说明。基本结论有以下两点:
一 从代码执行过程来看:
1.1 基本数据类型,将SrcValue赋值给Obj,有一个Box动作; Obj赋值给DesValue,有一个UnBox动作。
1.2 string数据类型,将SrcValue赋值给Obj,没有Box动作; 而将Obj赋值给DesValue,有一个强制类型转换。
1.3 自定义class类型,将SrcValue赋值给Obj,没有Box动作; 而将Obj赋值给DesValue,有一个强制类型转换。
二 从执行结果来看(将SrcValue赋值给Obj,再将Obj赋值给DesValue,再修改SrcValue):
2.1 基本数据类型,修改SrcValue后,DesValue没有变化
2.2 string数据类型,修改SrcValue后,DesValue没有变化
2.3 自定义class类型,修改SrcValue后,DesValue跟随变化
从中可以看出基本数据类型是值传递(即value),string是微软内置类型,和基本数据类型表现一致; 而自定义class型是引用传递(即reference)。
1 基本数据类型(以double为例)
源代码
private static void PlainType( )
{
double dSrcValue = 1.01;
object Obj = dSrcValue;
double dDesValue = (double)Obj;
System.Console.WriteLine("SrcValue = {0}", dSrcValue);
System.Console.WriteLine("DesValue = {0}", dDesValue);
System.Console.ReadKey();
System.Console.WriteLine("\n");
dSrcValue = 2.02;
System.Console.WriteLine("SrcValue = {0}", dSrcValue);
System.Console.WriteLine("DesValue = {0}", dDesValue);
System.Console.ReadKey();
}
static void Main(string[] args)
{
PlainType();
}
执行结果:
SrcValue = 1.01
DesValue = 1.01
SrcValue = 2.02
DesValue = 1.01
ildasm的代码:
.method private hidebysig static void PlainType() cil managed
{
// Code size 127 (0x7f)
.maxstack 2
.locals init ([0] float64 dSrcValue,
[1] object Obj,
[2] float64 dDesValue) // 变量在栈内存中初始化
IL_0000: nop
IL_0001: ldc.r8 1.01
IL_000a: stloc.0 // 赋值给dSrcValue
IL_000b: ldloc.0 // 加载dSrcValue的值
IL_000c: box [mscorlib]System.Double // 对dSrcValue进行Box处理
IL_0011: stloc.1 // 赋值给 Obj
IL_0012: ldloc.1 // 加载Obj的值
IL_0013: unbox.any [mscorlib]System.Double // UnBox
IL_0018: stloc.2 // 赋值给dDesValue
IL_0019: ldstr "SrcValue = {0}" // 加载格式化字符串
IL_001e: ldloc.0 // 加载dSrcValue值
IL_001f: box [mscorlib]System.Double // dSrcValue值Box处理
IL_0024: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_0029: nop
IL_002a: ldstr "DesValue = {0}" // 加载格式化字符串
IL_002f: ldloc.2 // 加载dDesValue
IL_0030: box [mscorlib]System.Double
IL_0035: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_003a: nop
IL_003b: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_0040: pop
IL_0041: ldstr "\n"
IL_0046: call void [mscorlib]System.Console::WriteLine(string)
IL_004b: nop
IL_004c: ldc.r8 2.02
IL_0055: stloc.0 // 赋值给dSrcValue
IL_0056: ldstr "SrcValue = {0}" // 加载格式化字符串
IL_005b: ldloc.0 // 加载dSrcValue值
IL_005c: box [mscorlib]System.Double // dSrcValue值Box处理
IL_0061: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_0066: nop
IL_0067: ldstr "DesValue = {0}" // 加载格式化字符串
IL_006c: ldloc.2 // 加载dDesValue
IL_006d: box [mscorlib]System.Double // dDesValue Box处理
IL_0072: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_0077: nop
IL_0078: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_007d: pop
IL_007e: ret
} // end of method Program::PlainType
2 string类型
源代码:
private static void StringType()
{
string SrcValue = "ABC";
object Obj = SrcValue;
string DesValue = (string)Obj;
System.Console.WriteLine("SrcValue = {0}", SrcValue);
System.Console.WriteLine("DesValue = {0}", DesValue);
System.Console.ReadKey();
System.Console.WriteLine("\n");
SrcValue = "DEF";
System.Console.WriteLine("SrcValue = {0}", SrcValue);
System.Console.WriteLine("DesValue = {0}", DesValue);
System.Console.ReadKey();
}
static void Main(string[] args)
{
StringType();
}
执行结果:
SrcValue = ABC
DesValue = ABC
SrcValue = DEF
DesValue = ABC
ildasm代码:
.method private hidebysig static void StringType() cil managed
{
// Code size 94 (0x5e)
.maxstack 2
.locals init ([0] string SrcValue,
[1] object Obj,
[2] string DesValue)
IL_0000: nop
IL_0001: ldstr "ABC" // 加载常量字符串"ABC"
IL_0006: stloc.0 // "ABC"赋给SrcValue
IL_0007: ldloc.0 // 加载SrcValue
IL_0008: stloc.1 // "ABC"赋值给Obj
IL_0009: ldloc.1 // 加载Obj
IL_000a: castclass [mscorlib]System.String // Obj类型转换为string类型
IL_000f: stloc.2 // 转换结果赋值给DesValue
IL_0010: ldstr "SrcValue = {0}"
IL_0015: ldloc.0
IL_0016: call void [mscorlib]System.Console::WriteLine(string,
object) // 打印字符串SrcValue
IL_001b: nop
IL_001c: ldstr "DesValue = {0}"
IL_0021: ldloc.2
IL_0022: call void [mscorlib]System.Console::WriteLine(string,
object) // 打印字符串DesValue
IL_0027: nop
IL_0028: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_002d: pop
IL_002e: ldstr "\n"
IL_0033: call void [mscorlib]System.Console::WriteLine(string)
IL_0038: nop
IL_0039: ldstr "DEF"
IL_003e: stloc.0 // 常量字符串"DEF"赋值给SrcValue
IL_003f: ldstr "SrcValue = {0}"
IL_0044: ldloc.0
IL_0045: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_004a: nop
IL_004b: ldstr "DesValue = {0}"
IL_0050: ldloc.2
IL_0051: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_0056: nop
IL_0057: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_005c: pop
IL_005d: ret
} // end of method Program::StringType
3 自定义class类型
源代码
class MyRefClass<T>
{
private T m_Value;
public T Value
{
set { m_Value = value; }
}
public MyRefClass(T _Value)
{
m_Value = _Value;
}
public T PrintValue()
{
return m_Value;
}
}
private static void RefClassType()
{
MyRefClass<double> SrcValue = new MyRefClass<double>(1.01);
object Obj = SrcValue;
MyRefClass<double> DesValue = (MyRefClass<double>)Obj;
System.Console.WriteLine("SrcValue = {0}", SrcValue.PrintValue());
System.Console.WriteLine("DesValue = {0}", DesValue.PrintValue());
System.Console.ReadKey();
System.Console.WriteLine("\n");
SrcValue.Value = 2.02;
System.Console.WriteLine("SrcValue = {0}", SrcValue.PrintValue());
System.Console.WriteLine("DesValue = {0}", DesValue.PrintValue());
System.Console.ReadKey();
}
static void Main(string[] args)
{
RefClassType();
}
执行结果:
SrcValue = 1.01
DesValue = 1.01
SrcValue = 2.02
DesValue = 2.02
ildasm代码:
.method private hidebysig static void RefClassType() cil managed
{
// Code size 153 (0x99)
.maxstack 2
.locals init ([0] class Boxing.MyRefClass`1<float64> SrcValue,
[1] object Obj,
[2] class Boxing.MyRefClass`1<float64> DesValue)
IL_0000: nop
IL_0001: ldc.r8 1.01
IL_000a: newobj instance void class Boxing.MyRefClass`1<float64>::.ctor(!0) // 创建MyRefClass对象
IL_000f: stloc.0 // 赋值给SrcValue
IL_0010: ldloc.0
IL_0011: stloc.1 // 赋值给Obj
IL_0012: ldloc.1
IL_0013: castclass class Boxing.MyRefClass`1<float64> // Obj类型转换
IL_0018: stloc.2 // 赋值给DesValue
IL_0019: ldstr "SrcValue = {0}"
IL_001e: ldloc.0
IL_001f: callvirt instance !0 class Boxing.MyRefClass`1<float64>::PrintValue()
IL_0024: box [mscorlib]System.Double
IL_0029: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_002e: nop
IL_002f: ldstr "DesValue = {0}"
IL_0034: ldloc.2
IL_0035: callvirt instance !0 class Boxing.MyRefClass`1<float64>::PrintValue()
IL_003a: box [mscorlib]System.Double
IL_003f: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_0044: nop
IL_0045: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_004a: pop
IL_004b: ldstr "\n"
IL_0050: call void [mscorlib]System.Console::WriteLine(string)
IL_0055: nop
IL_0056: ldloc.0
IL_0057: ldc.r8 2.02
IL_0060: callvirt instance void class Boxing.MyRefClass`1<float64>::set_Value(!0)
IL_0065: nop
IL_0066: ldstr "SrcValue = {0}"
IL_006b: ldloc.0
IL_006c: callvirt instance !0 class Boxing.MyRefClass`1<float64>::PrintValue()
IL_0071: box [mscorlib]System.Double
IL_0076: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_007b: nop
IL_007c: ldstr "DesValue = {0}"
IL_0081: ldloc.2
IL_0082: callvirt instance !0 class Boxing.MyRefClass`1<float64>::PrintValue()
IL_0087: box [mscorlib]System.Double
IL_008c: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_0091: nop
IL_0092: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_0097: pop
IL_0098: ret
} // end of method Program::RefClassType