博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个重写的ToString()方法引发的装箱
阅读量:5269 次
发布时间:2019-06-14

本文共 5806 字,大约阅读时间需要 19 分钟。

  昨天在看CLR的装箱拆箱时,对于值类型:同样的定义,一个在输出控制台时显示调用了重写的ToString()与另一个未显示调用ToString()方法时,前者不用装箱而后者需装箱时产生了疑惑。今天动手实验了下,在对其后台的IL代码分析得知果然如此。

定义代码:

 
1
namespace
ConsoleApplication3
2
{
3
internal
interface
IChangeBoxedPoint
4
{
5
void
Change(Int32 x, Int32 y);
6
}
7
internal
struct
Point : IChangeBoxedPoint
8
{
9
private
Int32 m_x, m_y;
10
11
public
Point(Int32 x, Int32 y)
12
{
13
m_x
=
x;
14
m_y
=
y;
15
}
16
public
void
Change(Int32 x, Int32 y)
17
{
18
m_x
=
x;
19
m_y
=
y;
20
}
21
22
23
public
override
string
ToString()
24
{
25
return
String.Format(
"
({0}, {1})
"
, m_x, m_y);
26
//
return base.ToString();
27
 
}
28
}
29
}

不显示调用上述 ToString()时代码:

 
class
Program
{
static
void
Main(
string
[] args)
{
Point p
=
new
Point(
1
,
1
);
Point p2
=
new
Point(
20
,
20
);
//
Console.WriteLine(p2.ToString());
Console.WriteLine(p2);
//
装箱,输出(20,20)
//
Console.WriteLine(p.ToString());
Console.WriteLine(p);
//
装箱,输出(1,1)
p.Change(
2
,
2
);
//
Console.WriteLine(p.ToString());
Console.WriteLine(p);
//
装箱,输出(2,2)
Object o
=
p;
//
装箱
Console.WriteLine(o);
//
不论显式调用.ToString()与否,上面都需装箱
#region
//
((Point)o).Change(3, 3);
//
Console.WriteLine(o.ToString());
//
Console.WriteLine(o);
//
((IChangeBoxedPoint)p).Change(4, 4);
//
Console.WriteLine(p);
//
((IChangeBoxedPoint)o).Change(5, 5);
//
Console.WriteLine(o);
#endregion
Console.ReadKey();
}
}

上述非显式调用时生成的IL代码:

 
.method
private
hidebysig
static
void
Main(
string
[] args) cil managed
{
.entrypoint
//
代码大小 90 (0x5a)
.maxstack
3
.locals init ([
0
] valuetype ConsoleApplication3.Point p,
[
1
] valuetype ConsoleApplication3.Point p2,
[
2
]
object
o)
IL_0000: nop
IL_0001: ldloca.s p
IL_0003: ldc.i4.
1
IL_0004: ldc.i4.
1
IL_0005: call instance
void
ConsoleApplication3.Point::.ctor(int32,
int32)
IL_000a: nop
IL_000b: ldloca.s p2
IL_000d: ldc.i4.s
20
IL_000f: ldc.i4.s
20
IL_0011: call instance
void
ConsoleApplication3.Point::.ctor(int32,
int32)
IL_0016: nop
IL_0017: ldloc.
1
IL_0018: box ConsoleApplication3.Point //对P2的装箱
IL_001d: call
void
[mscorlib]System.Console::WriteLine(
object
)
IL_0022: nop
IL_0023: ldloc.
0
IL_0024: box ConsoleApplication3.Point //对P的装箱
IL_0029: call
void
[mscorlib]System.Console::WriteLine(
object
)
IL_002e: nop
IL_002f: ldloca.s p
IL_0031: ldc.i4.
2
IL_0032: ldc.i4.
2
IL_0033: call instance
void
ConsoleApplication3.Point::Change(int32,
int32)
IL_0038: nop
IL_0039: ldloc.
0
IL_003a: box ConsoleApplication3.Point //对P的装箱
IL_003f: call
void
[mscorlib]System.Console::WriteLine(
object
)
IL_0044: nop
IL_0045: ldloc.
0
IL_0046: box ConsoleApplication3.Point //对P的装箱
IL_004b: stloc.
2
IL_004c: ldloc.
2
IL_004d: call
void
[mscorlib]System.Console::WriteLine(
object
)
IL_0052: nop
IL_0053: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_0058: pop
IL_0059: ret
}
//
end of method Program::Main

显示调用.ToString()方法时的代码:

ContractedBlock.gif
ExpandedBlockStart.gif
View Code
 
1
namespace
ConsoleApplication3
2
{
3
class
Program
4
{
5
static
void
Main(
string
[] args)
6
{
7
Point p
=
new
Point(
1
,
1
);
8
Point p2
=
new
Point(
20
,
20
);
9
10
Console.WriteLine(p2.ToString());
//
不装箱,输出(20,20)
11
//
Console.WriteLine(p2);
//
装箱,输出(20,20)
12
 
13
Console.WriteLine(p.ToString());
//
不装箱,输出(1,1)
14
//
Console.WriteLine(p);
//
装箱,输出(1,1)
15
 
16
p.Change(
2
,
2
);
17
Console.WriteLine(p.ToString());
//
不装箱,输出(2,2)
18
//
Console.WriteLine(p);
//
装箱,输出(2,2)
19
 
20
Object o
=
p;
//
装箱
21
//
Console.WriteLine(o);
//
不论显式调用.ToString()与否,上面都需装箱
22
 
Console.WriteLine(o.ToString());
//
不论显式调用.ToString()与否,上面都需装箱
23
 
#region
24
//
((Point)o).Change(3, 3);
25
//
Console.WriteLine(o.ToString());
26
//
Console.WriteLine(o);
27
28
29
//
((IChangeBoxedPoint)p).Change(4, 4);
30
//
Console.WriteLine(p);
31
32
//
((IChangeBoxedPoint)o).Change(5, 5);
33
//
Console.WriteLine(o);
34
 
#endregion
35
36
Console.ReadKey();
37
38
}
39
}
40
41
}

生成的IL代码:

 
1
.method
private
hidebysig
static
void
Main(
string
[] args) cil managed
2
{
3
.entrypoint
4
//
代码大小 116 (0x74)
5
 
.maxstack
3
6
.locals init ([
0
] valuetype ConsoleApplication3.Point p,
7
[
1
] valuetype ConsoleApplication3.Point p2,
8
[
2
]
object
o)
9
IL_0000: nop
10
IL_0001: ldloca.s p
11
IL_0003: ldc.i4.
1
12
IL_0004: ldc.i4.
1
13
IL_0005: call instance
void
ConsoleApplication3.Point::.ctor(int32,
14
int32)
15
IL_000a: nop
16
IL_000b: ldloca.s p2
17
IL_000d: ldc.i4.s
20
18
IL_000f: ldc.i4.s
20
19
IL_0011: call instance
void
ConsoleApplication3.Point::.ctor(int32,
20
int32)
21
IL_0016: nop
22
IL_0017: ldloca.s p2
23
IL_0019: constrained. ConsoleApplication3.Point
24
IL_001f: callvirt instance
string
[mscorlib]System.Object::ToString()
25
IL_0024: call
void
[mscorlib]System.Console::WriteLine(
string
)
26
IL_0029: nop
27
IL_002a: ldloca.s p
28
IL_002c: constrained. ConsoleApplication3.Point
29
IL_0032: callvirt instance
string
[mscorlib]System.Object::ToString()
30
IL_0037: call
void
[mscorlib]System.Console::WriteLine(
string
)
31
IL_003c: nop
32
IL_003d: ldloca.s p
33
IL_003f: ldc.i4.
2
34
IL_0040: ldc.i4.
2
35
IL_0041: call instance
void
ConsoleApplication3.Point::Change(int32,
36
int32)
37
IL_0046: nop
38
IL_0047: ldloca.s p
39
IL_0049: constrained. ConsoleApplication3.Point
40
IL_004f: callvirt instance
string
[mscorlib]System.Object::ToString()
41
IL_0054: call
void
[mscorlib]System.Console::WriteLine(
string
)
42
IL_0059: nop
43
IL_005a: ldloc.
0
44
IL_005b: box ConsoleApplication3.Point //唯一的一次装箱
45
IL_0060: stloc.
2
46
IL_0061: ldloc.
2
47
IL_0062: callvirt instance
string
[mscorlib]System.Object::ToString()
48
IL_0067: call
void
[mscorlib]System.Console::WriteLine(
string
)
49
IL_006c: nop
50
IL_006d: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
51
IL_0072: pop
52
IL_0073: ret
53
}
//
end of method Program::Main
      综上可知,当我们在值类型中重写了.ToString()方法时,如果能显示调用它最好显式调用,以减少不必要的装箱。

转载于:https://www.cnblogs.com/lixiangfa/archive/2011/04/10/2011181.html

你可能感兴趣的文章
qt实现类似QQ伸缩窗口--鼠标事件应用
查看>>
Ztree异步树加载
查看>>
复杂问题的简单抽象:魔兽世界中的兔子们
查看>>
UVA 10529-Dumb Bones(概率dp)
查看>>
关于IE和火狐,谷歌,Safari对Html标签Object和Embed的支持问题
查看>>
MyEclipse DB Browser使用图文全攻略
查看>>
poj3320 Jessica's Reading Problem(尺取思路+STL)
查看>>
A - Vasya and Socks
查看>>
项目管理、设计开发、代码管理、bug管理工具介绍
查看>>
分布式计算开源框架Hadoop介绍
查看>>
安卓平台接口剖析
查看>>
linux文件编码查看与修改
查看>>
[Java] 系统环境变量配置
查看>>
坏的事情不都会带来坏的结果
查看>>
RPC的基础:调研EOS插件http_plugin
查看>>
HIT1946 希尔伯特分形曲线(dfs)
查看>>
第二次团队冲刺第二天
查看>>
青瓷引擎之纯JavaScript打造HTML5游戏第二弹——《跳跃的方块》Part 2
查看>>
bzoj 2257 (JSOI 2009) 瓶子与燃料
查看>>
11)Java abstract class 和 interface
查看>>