一,IL访问静态属性和字段
一,IL访问静态属性和字段
通用中间语言(Common Intermediate Language,简称CIL,发音为"sill"或"kill")是一种属于通用语言架构和.NET框架的低阶(lowest-level)的人类可读的编程语言。目标为.NET 框架的语言被编译成CIL,然后汇编成字节码。CIL类似一个面向对象的汇编语言,并且它是完全基于堆栈的。它运行在虚拟机上,其主要的语言有C#、Visual Basic .NET、C++/CLI以及 J♯。
在.NET语言的测试版中,CIL原本叫做微软中间语言,即Microsoft Intermediate Language,简称MSIL。由于C#和通用语言架构的标准化,在.Net开发平台下,所有语言(C#、VB.NET、J#、Managed C++)都会被编译为MSIL,再由CLR负责运行,字节码现在已经官方地成为了CIL。因此,CIL仍旧经常与MSIL相提并论,特别是那些.NET语言的老用户。
以上引用自维基百科
简单的来说,就是.NET在编译C#编码时会由一个“C#代码编译组件”将C#代码编译为IL中间码,然后再由另一套组件将IL中间码编译为字节码
虽然IL码很复杂,不过编写一些简单的问题也不大。
下面就由浅入深的举几个栗子
我们先编译一个简单的方法AAA
using System;
using System.Collections.Generic;
using System.Text;
namespace blqw.IL.Demo
{
class Program
{
static void Main(string[] args)
{
}
public object AAA()
{
return MyClass.Name;
}
}
class MyClass
{
public static string Name { get; set; }
}
}
然后用reflector反射,看看生成的IL代码
先找到AAA方法,然后在语言的下拉框中选择IL
简单介绍一下每句IL的含义

.method public hidebysig instance object AAA() cil managed
{
.maxstack 1
.locals init (
[0] obje-0001ct CS$1$0000)//(以上的内容都不是我们需要关心的)
L_0000: nop //如果修补操作码,则填充空间。尽管可能消耗处理周期,但未执行任何有意义的操作。(也就是说这个步骤是么意义的)
L_0001: call string blqw.IL.Demo.MyClass::get_Name()//调用由传递的方法说明符指示的方法。(将返回值保存在堆栈中)
L_0006: stloc.0 //从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中。(将刚才的返回值,保存在locals[0],也就是那个CS$1$0000中)
L_0007: br.s L_0009//无条件地将控制转移到目标指令(类似于goto吧,跳转到下一行)
L_0009: ldloc.0 //将索引 0 处的局部变量加载到计算堆栈上。
L_000a: ret // 从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。(这句必须是方法中的最后一句,指示方法已经结束了,这时如果堆栈中有值,则返回值,没有则返回void)
}

上面注释中括号里的都是我写的,括号外的是微软官方的注释
仔细看就会发现,其实编译好的IL生成了很多不必要的操作
比如L_0000.连微软自家都说这个操作是无意义的,尽可能消耗时间而已..
还有L_0006~L_0009.都是无用的;连起来看就会发现,它先把堆栈中的值保存到变量0中,然后goto到下一行,然后再把变量0的值加载到堆栈上,结果堆栈上原来是什么值还是什么值
所以真正有用的只有L_0001和L_000a,一句是执行方法,一句是返回
好了现在我们按照这个思路自己写一个IL,只有2句啊,超简单有木有!!!!!!

public static Func<object> ILTest()
{
//编译li动态方法
//1.声明动态方法对象DynamicMethod
// 第一个参数是方法名,可以为空字符,不可以是null
// 第二个参数是动态方法返回值类型
// 第三个参数是Type[],表示方法参数,如果没有参数可以是null
// 第四个参数是声明逻辑关联类,可以让动态方法访问该类有权访问所有字段,包括逻辑关联类的私有字段
var dm = new DynamicMethod("", typeof(object), null, typeof(MyClass));
//2.声明il编译器
var il = dm.GetILGenerator();
//3.执行MyClass类的Name属性的Get方法 这句对应刚才的L_0001
il.Emit(OpCodes.Call, typeof(MyClass).GetProperty("Name").GetGetMethod());
//4.方法结束,这句对应刚才的L_000a
il.Emit(OpCodes.Ret);
//5.由il编译器创建指定类型的动态方法委托
return (Func<object>)dm.CreateDelegate(typeof(Func<object>));
}

去掉注释和方法声明,整个方法体才5行啊!
查看下运行结果
成功了!而且由于自己编写IL比微软生成好的代码少了好多,所以性能上更好
下面用一样的方法看看静态字段怎么访问
第一步,直接把MyClass的Name属性改为静态字段

class MyClass
{
public static string Name;
}

查看反编译的IL代码

.method public hidebysig instance object AAA() cil managed
{
.maxstack 1
.locals init (
[0] object CS$1$0000)
L_0000: nop
L_0001: ldsfld string blqw.IL.Demo.MyClass::Name
L_0006: stloc.0
L_0007: br.s L_0009
L_0009: ldloc.0
L_000a: ret
}

好吧,只有L_0001不一样了
对应C#中的代码更变:

public static Func<object> ILTest()
{
//编译li动态方法
//1.声明动态方法对象DynamicMethod
// 第一个参数是方法名,可以为空字符,不可以是null
// 第二个参数是动态方法返回值类型
// 第三个参数是Type[],表示方法参数,如果没有参数可以是null
// 第四个参数是声明逻辑关联类,可以让动态方法访问该类有权访问所有字段,包括逻辑关联类的私有字段
var dm = new DynamicMethod("", typeof(object), null, typeof(MyClass));
//2.声明il编译器
var il = dm.GetILGenerator();
//3.执行MyClass类的Name属性的Get方法 这句对应刚才的L_0001
//il.Emit(OpCodes.Call, typeof(MyClass).GetProperty("Name").GetGetMethod());
//OpCodes.Ldsfld : 将静态字段的值推送到计算堆栈上。
il.Emit(OpCodes.Ldsfld, typeof(MyClass).GetField("Name"));
//4.方法结束,这句对应刚才的L_000a
il.Emit(OpCodes.Ret);
//5.由il编译器创建指定类型的动态方法委托
return (Func<object>)dm.CreateDelegate(typeof(Func<object>));
}

执行结果和刚才一样的就不贴了
其实在刚才的方法注释中我就已经提到了,第三个参数是"逻辑关联类"
这个可以理解成你把这个动态方法编译到哪个类中去了,在这个动态方法中可以访问逻辑关联类可以访问的所有对象
把刚才的栗子改为私有的试下?

class MyClass
{
static string Name; //这个方法是为了给Name赋值用
public static void SetName(string name)
{
Name = name;
}
}


public static Func<object> ILTest()
{
//编译li动态方法
//1.声明动态方法对象DynamicMethod
// 第一个参数是方法名,可以为空字符,不可以是null
// 第二个参数是动态方法返回值类型
// 第三个参数是Type[],表示方法参数,如果没有参数可以是null
// 第四个参数是声明逻辑关联类,可以让动态方法访问该类有权访问所有字段,包括逻辑关联类的私有字段
var dm = new DynamicMethod("", typeof(object), null, typeof(MyClass));
//2.声明il编译器
var il = dm.GetILGenerator();
//3.执行MyClass类的Name属性的Get方法 这句对应刚才的L_0001
//il.Emit(OpCodes.Call, typeof(MyClass).GetProperty("Name").GetGetMethod());
//OpCodes.Ldsfld : 将静态字段的值推送到计算堆栈上。
il.Emit(OpCodes.Ldsfld, typeof(MyClass).GetField("Name", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static));//这里稍微改一下,反射到私有静态字段是要添加额外参数的
//4.方法结束,这句对应刚才的L_000a
il.Emit(OpCodes.Ret);
//5.由il编译器创建指定类型的动态方法委托
return (Func<object>)dm.CreateDelegate(typeof(Func<object>));
}

访问静态私有属性的方式基本雷同,反射私有属性的代码是:

typeof(MyClass).GetProperty("Name",System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).GetGetMethod(true);

昨天是情人节,早早就上床了
嗯..别误会,出去玩了下,累了,所以睡得比较早
.本来应该把静态属性和字段的设置也写完的,真的没时间的,马上要上班去了
下一篇再说属性设置吧,同时吧类型转换一起将了,到时候还可以搞点小破坏哈~~
一,IL访问静态属性和字段的更多相关文章
- 玩转动态编译 - 高级篇:一,IL访问静态属性和字段
IL介绍 通用中间语言(Common Intermediate Language,简称CIL,发音为"sill"或"kill")是一种属于通用语言架构和.NET ...
- 玩转动态编译 - 高级篇:二,IL设置静态属性,字段和类型转换
静态属性赋值 先来看 Reflector反射出的IL源码(感谢Moen的提示),这次用 Release模式编译,去掉那些无用的辅助指令 public void AAA(string s) { MyCl ...
- - 高级篇:二,IL设置静态属性,字段和类型转换
- 高级篇:二,IL设置静态属性,字段和类型转换 静态属性赋值 先来看 Reflector反射出的IL源码(感谢Moen的提示),这次用 Release模式编译,去掉那些无用的辅助指令 public ...
- 类实例化对象可以访问静态(static)方法,但是不能访问静态属性。
类-> 访问->静态方法(类的方法)->可以 类 ->访问->普通方法(对象的方法)->不可以(虽然方法里不用$this关键字时,可以!但不支持这种写法) 类-&g ...
- WPF整理-XAML访问静态属性
"XAML provides an easy way to set values of properties—type converters and the extended propert ...
- PHP 访问类中的静态属性
静态属性和普通属性不一样,静态属性只属于类本身而不属于类的任何实例,所以他们的访问方式也不一样.你可以把静态属性认为是存储在类当中的全局变量,而且你可以在任何地方通过类来访问它们. 在类本身中访问静态 ...
- PHP static静态属性和静态方法
这里分析了php面向对象中static静态属性和静态方法的调用.关于它们的调用(能不能调用,怎么样调用),需要弄明白了他们在内存中存放位置,这样就非常容易理解了.静态属性.方法(包括静态与非静态)在内 ...
- 不可或缺 Windows Native (19) - C++: 对象的动态创建和释放, 对象的赋值和复制, 静态属性和静态函数, 类模板
[源码下载] 不可或缺 Windows Native (19) - C++: 对象的动态创建和释放, 对象的赋值和复制, 静态属性和静态函数, 类模板 作者:webabcd 介绍不可或缺 Window ...
- php面向对象中static静态属性和静态方法的调用
这篇文章主要介绍了php面向对象中static静态属性和静态方法的调用,实例分析了static静态属性和静态方法的原理与调用技巧,需要的朋友可以参考下 本文实例讲述了php中static静态属性和静态 ...
随机推荐
- iOS8自适应布局视频教程
联系:http://www.elsyy.com/course/6480 这是颐和园最近录制iOS8视频课程.简介iOS8出现在自适应布局. 本教程的书,颐和园<ios8 swift编程指南> ...
- Uva 409-Excuses, Excuses!(串)
Judge Ito is having a problem with people subpoenaed for jury duty giving rather lame excuses in ord ...
- 我的MYSQL学习心得(十一)
原文:我的MYSQL学习心得(十一) 我的MYSQL学习心得(十一) 我的MYSQL学习心得(一) 我的MYSQL学习心得(二) 我的MYSQL学习心得(三) 我的MYSQL学习心得(四) 我的MYS ...
- Android开发之Mediaplayer
Android提供了常见的音频.视频的编码.解码机制.借助于多媒体类MediaPlayer的支持,开发者能够非常方便在在应用中播放音频.视频.本篇博客主要解说在Android平台下怎样播放一个音频文件 ...
- a链接bug
<a href=”javascript:void(0);” class="btn" id="btn"></a> 在ios系统中(andr ...
- 上海及周边地区产品技术创业QQ群:98905958
创业是一件骄傲的事,每一个行业里最棒人才都应该创业或參与创业或以一个创业者的心态进行职业远景规划: 创业是一件寻常的事,跟上班打工一样寻常,没有什么必须的前置条件才干够開始,也没有什么前置条件能保证我 ...
- SQL Server 2012的附件失败,与硬链接的问题
1.我在系统上做了硬链接,也就是把C盘的某个目录,映射为D盘. 2.把数据库文件mdf和ldf放入D盘.结果,SQL Server的企业管理器,无法从D盘里加载mdf或ldf文件,并且在目录下无法显示 ...
- jquery+html三级联动下拉框及详情页面加载时的select初始化问题
html写的三个下拉框,如下: <select name="ddlQYWZYJ" id="ddl_QYWZYJ" class="fieldsel ...
- SQL点滴3—一个简单的字符串分割函数
原文:SQL点滴3-一个简单的字符串分割函数 偶然在电脑里看到以前保存的这个函数,是将一个单独字符串切分成一组字符串,这里分隔符是英文逗号“,” 遇到其他情况只要稍加修改就好了 CREATE FUN ...
- jQuery.form Ajax无刷新上传错误 (jQuery.handleError is not a function) 解决方案
今天,随着ajaxfileupload时间firebug财报显示,"jQuery.handleError is not a function"错误.因为一旦使用jQuery.for ...