Emit学习(2) - IL - 值类型和引用类型(补)
上周末回家去享受生活了, 工作是为了更好的生活嘛, 所以我把生活, 工作分的比较开. 这几天不是很忙, 在学习工作技能的同时, 发点博文, 也算是做一个学习笔记
上篇中, 贴出的地址里面那位哥, 也有一篇值类型和引用类型的文章
来源:http://www.cnblogs.com/yingql/archive/2009/03/23/1420026.html
我这个和他的那个稍有不同, 各位看官, 请!
一、示例
public class Person
{
public string Name { get; set; } public int Age { get; set; }
} class Program
{
private Random rand = new Random(DateTime.Now.Millisecond); private Person person = new Person { Name = "Elvin", Age = }; private string pro = "pro"; private double dou = 3.14; static void Main(string[] args)
{
Console.WriteLine("Main");
Console.ReadKey();
}
}
反编译Program的构造函数, 代码如下:
public Program()
{
this.rand = new Random(DateTime.Now.Millisecond);
Person person = new Person {
Name = "Elvin",
Age = 0x1a
};
this.person = person;
this.pro = "pro";
this.dou = 3.14;
} .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack
.locals init (
[] class ConsoleApplication3.Person person,
[] valuetype [mscorlib]System.DateTime time) L_0000: ldarg. //加载this, 是一个地址, 将this沉底, 为一会的this.rand = new Random()服务
L_0001: call valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
L_0006: stloc. //初始化time, 为当前时间
L_0007: ldloca.s time //加载time的地址, 为什么加载地址呢, 一会详细介绍, 容我卖个关子 (1)
L_0009: call instance int32 [mscorlib]System.DateTime::get_Millisecond() //调用结构体Datetime的方法 L_000e: newobj instance void [mscorlib]System.Random::.ctor(int32) //new Random(), 将对象放入堆中, 然后把指向此对象的地址压栈
L_0013: stfld class [mscorlib]System.Random ConsoleApplication3.Program::rand //把刚刚得到的地址赋给rand, 实现this.rand = new Random()功能 L_0018: ldarg. //加载this地址,将this沉底, 为一会的this.person=person服务
L_0019: newobj instance void ConsoleApplication3.Person::.ctor() //new Person()
L_001e: stloc. //person = new Person(), 这里的person并不是this.person, 注意
L_001f: ldloc. //加载person, 为什么此处是用的ldloc, 而不是ldloca呢? 答案马上揭晓
L_0020: ldstr "Elvin" //加载 "Elvin" 字符串
L_0025: callvirt instance void ConsoleApplication3.Person::set_Name(string) //person.Name = "Elvin"
L_002a: nop L_002b: ldloc.
L_002c: ldc.i4.s 0x1a
L_002e: callvirt instance void ConsoleApplication3.Person::set_Age(int32)
L_0033: nop L_0034: ldloc. //加载person, 不是this.person
L_0035: stfld class ConsoleApplication3.Person ConsoleApplication3.Program::person //给this.person赋值, this.person=person L_003a: ldarg. //加载this, 这里加载this做什么? (2)
L_003b: ldstr "pro" //加载"pro"字符串
L_0040: stfld string ConsoleApplication3.Program::pro //this.pro = "pro" L_0045: ldarg.
L_0046: ldc.r8 3.14
L_004f: stfld float64 ConsoleApplication3.Program::dou
L_0054: ldarg.
L_0055: call instance void [mscorlib]System.Object::.ctor()
L_005a: nop
L_005b: ret
}
例子大家应该都能看得懂, 下面就揭晓上面的包袱
二、注意的点
在揭晓答案之前, 首先得开一扇窗户.
大家应该都知道, 值类型、引用类型是怎么存储的吧, 多的就不解释了, 上一幅图吧

2. stfld -- 好吧, 在讲第1点之前, 我还是想先将第2点
先看stfld的工作原理, 即堆栈转换行为如下:
按照先后顺序:
1.将一个对象引用或指针压入堆栈
2.将值压入堆栈
3.该值和对象的引用/指针从堆栈中弹出,对象的字段更新为替换的值
详细分析 : http://www.cnblogs.com/jackson0714/p/4995948.html
从上面可以看出, 是需要传地址的, 先传地址, 在传值, 接着调用stfld指令, 才能完成赋值操作, 所以这里传了个ldarg.0, 来完成this.pro="pro"功能
1. ldloc 与 ldloca
从上面的例子, 看到在使用Person的时候, 用的ldloc, 而使用DateTime的时候, 却使用了ldloca, 此处就能体现引用类型和值类型的区别了.
在调用方法的时候, 由于引用类型在栈中, 存放的就是地址, 所以可以直接实现调用内部方法的功能,
而值类型并不是直接存放地址的, 所以在调用内部方法的时候, 其实是传地址来实现此功能的.
对象,结构体(值类型本质也是结构体, 如:int, decimal)在调用自身方法/属性/字段的时候, 都是通过传递地址的方式来调用的. time.Year(), 此处的time就是地址, person.Name, 此处的person也是一个地址
这哥们对IL有一个比较详细的介绍:http://www.cnblogs.com/jackson0714/p/DotNET_IL3.html#_label4
Emit学习(2) - IL - 值类型和引用类型(补)的更多相关文章
- C#学习笔记之值类型与引用类型
[TOC] C#学习笔记之值类型与引用类型 1.值类型与引用类型 1.1 深层区别 值类型与引用类型有不同的内存分布,这导致了不同的内存管理机制: 值类型由OS负责内存管理 引用类型由垃圾回收器(GC ...
- 学习记录 java 值类型和引用类型的知识
1. Java中值类型和引用类型的不同? [定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值, 那么调用这个方法是传入的变量的值也将改变 ...
- 【C#】学习笔记(4) 值类型和引用类型相关(Null相关)
Reference and Value Types Value Types(值类型): struct(结构体) 独立的实例或者是拷贝 值的改变不会影响其它拷贝 值就是它所代表的信息 没有引用,所以不可 ...
- C#学习笔记(基础知识回顾)之值类型和引用类型
一:C#把数据类型分为值类型和引用类型 1.1:从概念上来看,其区别是值类型直接存储值,而引用类型存储对值的引用. 1.2:这两种类型在内存的不同地方,值类型存储在堆栈中,而引用类型存储在托管对上.存 ...
- .net学习之.net和C#关系、运行过程、数据类型、类型转换、值类型和引用类型、数组以及方法参数等
1..net 和 C# 的关系.net 是一个平台,C#是种语言,C#语言可以通过.net平台来编写.部署.运行.net应用程序,C#通过.net平台开发.net应用程序2..net平台的重要组成FC ...
- C#学习笔记(三):值类型、引用类型及参数传递
值类型和引用类型简介 C#中存在两种数据类型,分别是值类型与引用类型,下面我们来看看这两种类型的区别. 值类型主要包括: 简单类型(如int.float.char等,注意string不是值类型): 枚 ...
- c#学习基础(2)存储、值类型和引用类型、变量
程序运行时,它的数据必须存储在内存中,数据项需要多大的内存.存储在什么地方以及如何存储都依赖该数据项的类型 运行中的程序使用两个区域来存储数据:栈和堆 栈是一个内存数组,是一个LIFO(last in ...
- Net基础篇_学习笔记_第十二天_面向对象继承(命名空间 、值类型和引用类型)
命名空间可以认为类是属于命名空间的. 解决类的重名问题,可以看做类的“文件夹”如果在当前项目中没有这个类的命名空间,需要我们手动的导入这个类所在的命名空间.1).用鼠标去点2).alt+shift+F ...
- 从CLR角度来看值类型与引用类型
前言 本文中大部分示例代码来自于<CLR via C# Edition3>,并在此之上加以总结和简化,文中只是重点介绍几个比较有共性的问题,对一些细节不会做过深入的讲解. 前几天一直忙着翻 ...
随机推荐
- 100天后 - 100-days-later
赛斯·高汀(Seth Godin)的博客: http://sethgodin.typepad.com/seths_blog/2013/04/100-days-later.html 面对着数以千计的图 ...
- git 仓库、分支的区别
首先,要明白仓库的概念 仓库可以理解为repository, 就是存放代码的地方,—— 其实是一个比较笼统的概念,不管里面的内容,总之存放各种资源(代码.图片等等) 对于git应用开发者而已,本地一般 ...
- Atitit. Api 设计 原则 ---归一化
Atitit. Api 设计 原则 ---归一化 1.1. 叫做归一化1 1.2. 归一化的实例:一切对象都可以序列化/toString 通过接口实现1 1.3. 泛文件概念.2 1.4. 游戏行业 ...
- Atitit 为什么网络会有延时 电路交换与分组交换的区别
Atitit 为什么网络会有延时 电路交换与分组交换的区别 按道理,网络是电子设备联网,应该达到光速才对.. 本质上因为互联网基于分组交换而不是电路交换. 分组交换相当于队列方式,别人发你的数据包先存 ...
- 【管理心得之三十八】如果“Q”不是高富帅,也吸引不了白富美“A”
场景再现=========================={美剧片段}一位老人在电话亭中,一次又一次地向公用电话投硬币,但是每一次仅是接通后就自动掉线了.老人无奈之下寻求他人拨打报修电话,但苦等了许 ...
- 用Chrome插件对自动化测试TestWriter进行录制
1.打开Chrome浏览器,在浏览地址中输入: chrome://extensions/,并勾选开发者模式.如图: 2.点击按钮[加载已解压的扩展程序-].如图: 3.选择Testwriter客户端下 ...
- 【WP 8.1开发】推送通知测试服务端程序
所谓推送通知,用老爷爷都能听懂的话说,就是: 1.我的服务器将通知内容发送到微软的通知服务器,再由通知服务器帮我转发消息. 2.那么,微软的推送服务器是如何知道我的服务器要发消息给哪台手机呢?手机客户 ...
- MVVM模式下,ViewModel和View,Model有什么区别
摘自正美的5群 Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就是展现出来的用户界面. 基本上,绝大多数软件所做的工 ...
- TTAS Lock C++11 实现
template<class Lock> class Lock_guard{ private: Lock lock; public: explicit Lock_guard(Lock&am ...
- c++中关于初始化型参列表的一些问题
/* 1.成员是按照他们在类中出现的顺序进行初始化的,而不是按照他们在初始化列表出现的顺序初始化的! 一个好的习惯是,按照成员定义的顺序进行初始化. 2.数组成员在初始化型参列表中不正确 */ #in ...