上周末回家去享受生活了, 工作是为了更好的生活嘛, 所以我把生活, 工作分的比较开. 这几天不是很忙, 在学习工作技能的同时, 发点博文, 也算是做一个学习笔记

上篇中, 贴出的地址里面那位哥, 也有一篇值类型和引用类型的文章

来源: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 - 值类型和引用类型(补)的更多相关文章

  1. C#学习笔记之值类型与引用类型

    [TOC] C#学习笔记之值类型与引用类型 1.值类型与引用类型 1.1 深层区别 值类型与引用类型有不同的内存分布,这导致了不同的内存管理机制: 值类型由OS负责内存管理 引用类型由垃圾回收器(GC ...

  2. 学习记录 java 值类型和引用类型的知识

    1. Java中值类型和引用类型的不同? [定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值, 那么调用这个方法是传入的变量的值也将改变 ...

  3. 【C#】学习笔记(4) 值类型和引用类型相关(Null相关)

    Reference and Value Types Value Types(值类型): struct(结构体) 独立的实例或者是拷贝 值的改变不会影响其它拷贝 值就是它所代表的信息 没有引用,所以不可 ...

  4. C#学习笔记(基础知识回顾)之值类型和引用类型

    一:C#把数据类型分为值类型和引用类型 1.1:从概念上来看,其区别是值类型直接存储值,而引用类型存储对值的引用. 1.2:这两种类型在内存的不同地方,值类型存储在堆栈中,而引用类型存储在托管对上.存 ...

  5. .net学习之.net和C#关系、运行过程、数据类型、类型转换、值类型和引用类型、数组以及方法参数等

    1..net 和 C# 的关系.net 是一个平台,C#是种语言,C#语言可以通过.net平台来编写.部署.运行.net应用程序,C#通过.net平台开发.net应用程序2..net平台的重要组成FC ...

  6. C#学习笔记(三):值类型、引用类型及参数传递

    值类型和引用类型简介 C#中存在两种数据类型,分别是值类型与引用类型,下面我们来看看这两种类型的区别. 值类型主要包括: 简单类型(如int.float.char等,注意string不是值类型): 枚 ...

  7. c#学习基础(2)存储、值类型和引用类型、变量

    程序运行时,它的数据必须存储在内存中,数据项需要多大的内存.存储在什么地方以及如何存储都依赖该数据项的类型 运行中的程序使用两个区域来存储数据:栈和堆 栈是一个内存数组,是一个LIFO(last in ...

  8. Net基础篇_学习笔记_第十二天_面向对象继承(命名空间 、值类型和引用类型)

    命名空间可以认为类是属于命名空间的. 解决类的重名问题,可以看做类的“文件夹”如果在当前项目中没有这个类的命名空间,需要我们手动的导入这个类所在的命名空间.1).用鼠标去点2).alt+shift+F ...

  9. 从CLR角度来看值类型与引用类型

    前言 本文中大部分示例代码来自于<CLR via C# Edition3>,并在此之上加以总结和简化,文中只是重点介绍几个比较有共性的问题,对一些细节不会做过深入的讲解. 前几天一直忙着翻 ...

随机推荐

  1. 100天后 - 100-days-later

    赛斯·高汀(Seth Godin)的博客:  http://sethgodin.typepad.com/seths_blog/2013/04/100-days-later.html 面对着数以千计的图 ...

  2. git 仓库、分支的区别

    首先,要明白仓库的概念 仓库可以理解为repository, 就是存放代码的地方,—— 其实是一个比较笼统的概念,不管里面的内容,总之存放各种资源(代码.图片等等) 对于git应用开发者而已,本地一般 ...

  3. Atitit. Api 设计 原则 ---归一化

    Atitit. Api 设计 原则 ---归一化 1.1. 叫做归一化1 1.2. 归一化的实例:一切对象都可以序列化/toString  通过接口实现1 1.3. 泛文件概念.2 1.4. 游戏行业 ...

  4. Atitit 为什么网络会有延时 电路交换与分组交换的区别

    Atitit 为什么网络会有延时 电路交换与分组交换的区别 按道理,网络是电子设备联网,应该达到光速才对.. 本质上因为互联网基于分组交换而不是电路交换. 分组交换相当于队列方式,别人发你的数据包先存 ...

  5. 【管理心得之三十八】如果“Q”不是高富帅,也吸引不了白富美“A”

    场景再现=========================={美剧片段}一位老人在电话亭中,一次又一次地向公用电话投硬币,但是每一次仅是接通后就自动掉线了.老人无奈之下寻求他人拨打报修电话,但苦等了许 ...

  6. 用Chrome插件对自动化测试TestWriter进行录制

    1.打开Chrome浏览器,在浏览地址中输入: chrome://extensions/,并勾选开发者模式.如图: 2.点击按钮[加载已解压的扩展程序-].如图: 3.选择Testwriter客户端下 ...

  7. 【WP 8.1开发】推送通知测试服务端程序

    所谓推送通知,用老爷爷都能听懂的话说,就是: 1.我的服务器将通知内容发送到微软的通知服务器,再由通知服务器帮我转发消息. 2.那么,微软的推送服务器是如何知道我的服务器要发消息给哪台手机呢?手机客户 ...

  8. MVVM模式下,ViewModel和View,Model有什么区别

    摘自正美的5群 Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就是展现出来的用户界面. 基本上,绝大多数软件所做的工 ...

  9. TTAS Lock C++11 实现

    template<class Lock> class Lock_guard{ private: Lock lock; public: explicit Lock_guard(Lock&am ...

  10. c++中关于初始化型参列表的一些问题

    /* 1.成员是按照他们在类中出现的顺序进行初始化的,而不是按照他们在初始化列表出现的顺序初始化的! 一个好的习惯是,按照成员定义的顺序进行初始化. 2.数组成员在初始化型参列表中不正确 */ #in ...