首先,在这里使用了大量的Emit和反射,因为不喜欢直接写IL汇编,所以看起来有点累,但是IL的知识是必须的,否则很难看明白这些代码是在干什么。
其次,要理解为什么会这样,需要了解一些程序底层的知识。
最后,准确的说,这里的对象并不是一个真实的对象,仅仅是把某段内存认为是某个对象,一般的高级语言不允许这样的代码,所以只能用最基础的IL来做。
1
static
void
Foo()
2![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3
AssemblyName name = new AssemblyName("a");
4
AssemblyBuilder a = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
5
ModuleBuilder m = a.DefineDynamicModule("test", false);
6
TypeBuilder tb = Bar(m);
7
Type t = tb.CreateType();
8
MethodInfo mi = t.GetMethod("test", BindingFlags.Public | BindingFlags.Static);
9
mi.Invoke(null, null);
10
}
11![](/Images/OutliningIndicators/None.gif)
12
static
TypeBuilder Bar(ModuleBuilder m)
13![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
14
// 创建一个Foo类
15
TypeBuilder result = m.DefineType("Foo");
16
// 定义一个bar字段
17
FieldBuilder field = result.DefineField("bar", typeof(int), FieldAttributes.Assembly);
18
// Foo的实例构造器
19
ConstructorBuilder ctor = result.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
20
ILGenerator gen = ctor.GetILGenerator();
21
gen.Emit(OpCodes.Ldarg_0);
22
gen.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
23
gen.Emit(OpCodes.Ldarg_0);
24
gen.Emit(OpCodes.Ldc_I4_0);
25
gen.Emit(OpCodes.Stfld, field);
26
gen.Emit(OpCodes.Ret);
27![](/Images/OutliningIndicators/InBlock.gif)
28
// 定义test方法
29
MethodBuilder method = result.DefineMethod("test",
30
MethodAttributes.Public | MethodAttributes.Static,
31
CallingConventions.Standard, typeof(void), Type.EmptyTypes);
32![](/Images/OutliningIndicators/InBlock.gif)
33
gen = method.GetILGenerator();
34
// 定义本地变量1、2、3
35
LocalBuilder local1 = gen.DeclareLocal(typeof(int));
36
LocalBuilder local2 = gen.DeclareLocal(typeof(int));
37
LocalBuilder local3 = gen.DeclareLocal(typeof(int));
38![](/Images/OutliningIndicators/InBlock.gif)
39
// 用local2的地址作为对象地址,调用实例构造器
40
gen.Emit(OpCodes.Ldloca, local2);
41
gen.Emit(OpCodes.Call, ctor);
42
// 用local2的地址作为对象地址,把数字123放到字段里面
43
gen.Emit(OpCodes.Ldloca, local2);
44
gen.Emit(OpCodes.Ldc_I4, 123);
45
gen.Emit(OpCodes.Stfld, field);
46![](/Images/OutliningIndicators/InBlock.gif)
47
// 来看看local1里面是什么
48
gen.Emit(OpCodes.Ldstr, "local1 address=");
49![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[]
{ typeof(string) }));
50
gen.Emit(OpCodes.Ldloca, local1);
51![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]
{ typeof(int) }));
52
gen.Emit(OpCodes.Ldstr, "local1=");
53![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[]
{ typeof(string) }));
54
gen.Emit(OpCodes.Ldloc, local1);
55![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]
{ typeof(int) }));
56
// 来看看local2里面是什么
57
gen.Emit(OpCodes.Ldstr, "local2 address=");
58![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[]
{ typeof(string) }));
59
gen.Emit(OpCodes.Ldloca, local2);
60![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]
{ typeof(int) }));
61
gen.Emit(OpCodes.Ldstr, "local2=");
62![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[]
{ typeof(string) }));
63
gen.Emit(OpCodes.Ldloc, local2);
64![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]
{ typeof(int) }));
65
// 来看看local3里面是什么
66
gen.Emit(OpCodes.Ldstr, "local3 address=");
67![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[]
{ typeof(string) }));
68
gen.Emit(OpCodes.Ldloca, local3);
69![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]
{ typeof(int) }));
70
gen.Emit(OpCodes.Ldstr, "local3=");
71![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[]
{ typeof(string) }));
72
gen.Emit(OpCodes.Ldloc, local3);
73![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]
{ typeof(int) }));
74![](/Images/OutliningIndicators/InBlock.gif)
75
// 用local2的地址作为对象地址,看看字段里面是什么
76
gen.Emit(OpCodes.Ldstr, "Field address=");
77![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[]
{ typeof(string) }));
78
gen.Emit(OpCodes.Ldloca, local2);
79
gen.Emit(OpCodes.Ldflda, field);
80![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]
{ typeof(int) }));
81
gen.Emit(OpCodes.Ldstr, "Field =");
82![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[]
{ typeof(string) }));
83
gen.Emit(OpCodes.Ldloca, local2);
84
gen.Emit(OpCodes.Ldfld, field);
85![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]
{ typeof(int) }));
86![](/Images/OutliningIndicators/InBlock.gif)
87
gen.Emit(OpCodes.Ret);
88![](/Images/OutliningIndicators/InBlock.gif)
89
return result;
90
}
91
![](/Images/OutliningIndicators/None.gif)
2
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
3
![](/Images/OutliningIndicators/InBlock.gif)
4
![](/Images/OutliningIndicators/InBlock.gif)
5
![](/Images/OutliningIndicators/InBlock.gif)
6
![](/Images/OutliningIndicators/InBlock.gif)
7
![](/Images/OutliningIndicators/InBlock.gif)
8
![](/Images/OutliningIndicators/InBlock.gif)
9
![](/Images/OutliningIndicators/InBlock.gif)
10
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
11
![](/Images/OutliningIndicators/None.gif)
12
![](/Images/OutliningIndicators/None.gif)
13
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
14
![](/Images/OutliningIndicators/InBlock.gif)
15
![](/Images/OutliningIndicators/InBlock.gif)
16
![](/Images/OutliningIndicators/InBlock.gif)
17
![](/Images/OutliningIndicators/InBlock.gif)
18
![](/Images/OutliningIndicators/InBlock.gif)
19
![](/Images/OutliningIndicators/InBlock.gif)
20
![](/Images/OutliningIndicators/InBlock.gif)
21
![](/Images/OutliningIndicators/InBlock.gif)
22
![](/Images/OutliningIndicators/InBlock.gif)
23
![](/Images/OutliningIndicators/InBlock.gif)
24
![](/Images/OutliningIndicators/InBlock.gif)
25
![](/Images/OutliningIndicators/InBlock.gif)
26
![](/Images/OutliningIndicators/InBlock.gif)
27
![](/Images/OutliningIndicators/InBlock.gif)
28
![](/Images/OutliningIndicators/InBlock.gif)
29
![](/Images/OutliningIndicators/InBlock.gif)
30
![](/Images/OutliningIndicators/InBlock.gif)
31
![](/Images/OutliningIndicators/InBlock.gif)
32
![](/Images/OutliningIndicators/InBlock.gif)
33
![](/Images/OutliningIndicators/InBlock.gif)
34
![](/Images/OutliningIndicators/InBlock.gif)
35
![](/Images/OutliningIndicators/InBlock.gif)
36
![](/Images/OutliningIndicators/InBlock.gif)
37
![](/Images/OutliningIndicators/InBlock.gif)
38
![](/Images/OutliningIndicators/InBlock.gif)
39
![](/Images/OutliningIndicators/InBlock.gif)
40
![](/Images/OutliningIndicators/InBlock.gif)
41
![](/Images/OutliningIndicators/InBlock.gif)
42
![](/Images/OutliningIndicators/InBlock.gif)
43
![](/Images/OutliningIndicators/InBlock.gif)
44
![](/Images/OutliningIndicators/InBlock.gif)
45
![](/Images/OutliningIndicators/InBlock.gif)
46
![](/Images/OutliningIndicators/InBlock.gif)
47
![](/Images/OutliningIndicators/InBlock.gif)
48
![](/Images/OutliningIndicators/InBlock.gif)
49
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
50
![](/Images/OutliningIndicators/InBlock.gif)
51
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
52
![](/Images/OutliningIndicators/InBlock.gif)
53
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
54
![](/Images/OutliningIndicators/InBlock.gif)
55
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
56
![](/Images/OutliningIndicators/InBlock.gif)
57
![](/Images/OutliningIndicators/InBlock.gif)
58
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
59
![](/Images/OutliningIndicators/InBlock.gif)
60
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
61
![](/Images/OutliningIndicators/InBlock.gif)
62
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
63
![](/Images/OutliningIndicators/InBlock.gif)
64
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
65
![](/Images/OutliningIndicators/InBlock.gif)
66
![](/Images/OutliningIndicators/InBlock.gif)
67
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
68
![](/Images/OutliningIndicators/InBlock.gif)
69
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
70
![](/Images/OutliningIndicators/InBlock.gif)
71
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
72
![](/Images/OutliningIndicators/InBlock.gif)
73
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
74
![](/Images/OutliningIndicators/InBlock.gif)
75
![](/Images/OutliningIndicators/InBlock.gif)
76
![](/Images/OutliningIndicators/InBlock.gif)
77
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
78
![](/Images/OutliningIndicators/InBlock.gif)
79
![](/Images/OutliningIndicators/InBlock.gif)
80
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
81
![](/Images/OutliningIndicators/InBlock.gif)
82
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
83
![](/Images/OutliningIndicators/InBlock.gif)
84
![](/Images/OutliningIndicators/InBlock.gif)
85
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
86
![](/Images/OutliningIndicators/InBlock.gif)
87
![](/Images/OutliningIndicators/InBlock.gif)
88
![](/Images/OutliningIndicators/InBlock.gif)
89
![](/Images/OutliningIndicators/InBlock.gif)
90
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
91
![](/Images/OutliningIndicators/None.gif)
乍一看,代码有些长,下面仔细分析一下:
1、Foo方法,作用是为Emit做准备,并且测试,调用"test"方法
2、Bar方法,Emit一个叫"Foo"的引用类型的类,带有一个"Bar"的字段,并且有一个实例构造器和一个"test"方法
3、在实例构造器中,对"Bar"字段赋初始值0
4、在"test"方法中,用local2的地址作为对象的地址,Call实例构造器(注意不能用newobj),这样的效果等于初始化对象的初始值(也就是说,Call实例构造器后,"Bar"字段的值就是构造器中赋的初始值)
5、再次用local2的地址作为对象的地址,给"Bar"字段赋数字123(注意,只有这里出现了123这个数字)
6、从控制台分别输出local1、local2、local3,以及用local2的地址作为对象的地址的"Bar"字段的内存地址和他们的值
代码的作用就是这些,看一下运行的结果:
local1 address
=
1240840
local1 = 123
local2 address = 1240836
local2 = 0
local3 address = 1240832
local3 = 0
Field address = 1240840
Field = 123
local1 = 123
local2 address = 1240836
local2 = 0
local3 address = 1240832
local3 = 0
Field address = 1240840
Field = 123
运行结果中,可以意外的发现,local1也是123,而且local1的地址和"Bar"字段的地址一致。
当然这个值并不固定,而且local1、local2、local3的地址并不一定是递减的,也有可能是递增的,或者其它情况(虽然还没遇到,但是也不排除有分散的可能性)。
在递减的情况下,local1与以local2的地址作为对象地址的"Bar"字段的地址是一致的,也就是说,以local2的地址作为对象地址的情况下,"Bar"字段并不是在堆上,而是在栈上。对local1的任何改动可以影响"Bar"字段,反过来,对"Bar"字段的任何改动也可以影响local1,因为本质上它们就是同一个地址。
同样,以local2的地址作为对象地址的这个虚假引用类型的"对象",也是存在于栈上的,是从local2地址开始的,一片隶属于栈的内存。
最后,需要注意的一点是,这个方法有种钻运行时漏洞的感觉,在x86 .net 2.0的环境上测试通过,不保证其它运行时也能正常运行。