编译器开关设置 IL代码质量 JIT本地代码质量
/optimize- /debug-(默认设置) 未优化 优化
/optimize- /debug+(full/pdbonly) 未优化 未优化
/optimize+ /debug+(/-/full/pdbonly) 优化 优化

2.类型基础,类型转换

Object类型的方法

❶GetType()为非虚方法,所以其他类型不能改变这个这个函数的返回值

从值类型调用GetType()会有一次装箱,以将【对象类型指针】指向对应的类型(type)对象

【对象类型指针】:在CLR via C#上有讲,比较清楚,堆上的对象所需要的开销字段之一,另一个是同步块索引

❷Equal方法,重写Equal,IEquatble<T>

Equal方法是判断相等性,CLR via C#书上说的Object的Equal实例方法只是简单调用==运算符,判断的是一致性(identity),即和静态方法ReferenceEqual一样,我那Reflector看,最后调用的RuntimeHelper extern方法,怎么实现的也不得而知.

所有的值类型,如Struct继承自System.ValueType,重写的Equal如下

 [SecuritySafeCritical, __DynamicallyInvokable]
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
RuntimeType type = (RuntimeType) base.GetType();
RuntimeType type2 = (RuntimeType) obj.GetType();
if (type2 != type)
{
return false;
}
object a = this;
if (CanCompareBits(this))
{
return FastEqualsCheck(a, obj);
}
FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
for (int i = ; i < fields.Length; i++)
{
object obj3 = ((RtFieldInfo) fields[i]).UnsafeGetValue(a);
object obj4 = ((RtFieldInfo) fields[i]).UnsafeGetValue(obj);
if (obj3 == null)
{
if (obj4 != null)
{
return false;
}
}
else if (!obj3.Equals(obj4))
{
return false;
}
}
return true;
}

通过比较值,我们来看看int结构的源码

上面一个object类型参数的是重写继承自ValueType的Equals,下面那个是实现IEquatable<int>接口

调用的是int的==的操作符,==默认比较的引用,在ValueType类中没有找到任何重载运算符的code,对于这个==操作符,在园子搜到的说是值类型==比较值,引用类型==比较引用,在自定义值类型如果不重载==运算符,就无法使用==运算符

Summary:对于我们自定义类型,如果要重写Equals,也重写下GetHashCode(),这个GetHashCode在HashTable,Dictionary中用来存储,索引键,同时可以实现IEquatable<T>接口,在override的Equals中调用这个参数为T的方法.要是参与比较,可以实现IComparable<int>,可以供Equals,以及运算符重载(> >= < <=)使用

参考http://msdn.microsoft.com/zh-cn/library/ms173147.aspx

隐式转换,强制转换

Object o=new Person();//可以自动将new出来的Person隐式转换Person类的任何基类

Person p=(Person)o;//强制类型转换,显式指定,可将一个实例强制转换为new 类型,以及该构造类型的基类

上面的转化在Base class,Derived class之间的转换,不需要编写额外的代码.

关于Implicit(隐式)和explicit(显式)转换

这俩单词总是记不住,搞混,上面的转换是不需要code的,在不能转换的时候,会抛出InvalidCastException,但有的时候,我们就知道怎么在不相关的实例中转换,需要在代码中给出转换方法

public static implicit operator 转换到的类型(原类型)//implicit可以在本类里面互转

public static implicit operator ClassA(ClassB b);//将ClassB隐式转换为ClassA

public static implicit operator ClassB(ClassA a);//将ClassA隐式转换为ClassB

这两个转换都可以在一个类中完成

public static explicit operator 转换到的类型(本类型-即当前类)

如果要将ClassA转为ClassB

只能在ClassA里面定义public static explicit operator ClassB(ClassA a);//显式转换要求被转类型必须是当前类

msdn:http://msdn.microsoft.com/zh-cn/library/z5z9kes2.aspx

3.as is 强制类型转换

abc as ABC等价于(abc is ABC) ?(ABC)abc :null

之前写代码的时候,总是想,as 和 is是哪个调用哪个呢,其实as调用is,再加强制类型转换

我以前喜欢这样写

if(abc is ABC)
{
  abc as ABC;
  blabla...
}

其实我这样写判断了两次abc的类型,再if里面直接用强制类型转换即可

4.StructLayout,LayoutKind. (Auto/Sequential,Explicit)

定义struct可以看到有System.InteropServices.StructLayoutAttribute(LayoutKind.xxx)出现

这个特性可以决定CLR如何排列类 or 结构 中的字段,

Sequential:让CLR保持字段的排列;

Auto:让CLR来优化处理,可能会被压缩,分组等;

Explicit:显式地指出偏移量,来决定如何排列

结构体(Struct)默认为Sequential,经常用于与非托管C/C++代码打交道,如果确定不用于与非托管代码交互,可改为Auto来让CLR优化性能

类默认就是Auto,CLR优化

5.IL中Call与Callvirt

call用来调用

❶静态方法,指定类型,方法

❷实例方法,call调用实例方法时,会假设变量!=null

❸特殊情况下的虚方法,非虚拟的调用虚方法,下文解释

callvirt

❶非虚实例方法,callvirt会检查当前实例是否为null,如果是,会抛出NullReferenceException

❷虚方法,call virtual,应该就是这个的缩写,调用一个虚方法时,会查找对象的实际类型,多方面地调用虚方法...

  这个说的也是文邹邹的,调用虚方法

  1.如果是ABC abc=new ABC类型的,从该类以及父类中寻找被调用的方法,比较常规

  2.像Base instance=new Derived(),父类声明,new 子类的情况,是从父类Base中开始寻找,如果找到,而且标记为virtual,而且子类中有相应的override,就调用子类的override实现,就是所谓的多态了.

在call中的第三条,call 虚方法,是这样一种情况:在C#编译器已知本次方法调用不会有多态存在的情况下,会生成call 虚方法指令,

例如

class Abc
{
  public override void ToSTring()
  {
    return base.ToString();//本行代码会生成call指令,调用ToString()虚方法
  }
}

这个类Abc继承自Object,重写了ToString方法,在return base.ToSTring()时如果再用callvirt Object的ToString时,会导致递归调用,直至栈溢出,所以当不存在多态的情况下,虚方法调用也会生成call指令,再一个常见的是自己写一个Struct,override一个方法,然后调用一下,绝壁生成的call,因为结构体不允许继承,所以也没有谁来override它的方法

6.委托

委托,事件,lambda表达式,都是很常用的东西.

委托,类似函数指针,定义一个委托之后,会被编译成一个类,继承自MulticastDelegate,这个MulticastDelegate又继承自Delegate类

委托中有三个私有字段

_target 表示目标,如果委托代表的是静态函数,那么_target即为null,若是实例成员,则_target即为这个实例

_methodPtr 函数指针,指向所代表的函数

_invocationList 表示执行链,当委托只是代表着一个函数时,此字段为空

委托暴露两个公开属性

Target:对应上面的_target

Method : MethodInfo类型,表示委托代表的函数

委托编译成的类,会有一个构造方法(Object target,Intptr method)

一个Invoke函数,执行这个委托,还有BeginInvoke,EndInvoke 异步编程模式里面通用的

多播委托

Delegate.Combine/Delegate.Remove    可以将两个委托连起来/剔除

而且重载了+=,-=运算符,以快速调用

在一个委托被combine了很多其他签名符合的委托时,_target,_method均不重要了,也就是不会被调用了,而它的invocationList是被连接过的委托数组,代表着执行链,当委托执行时,会依次执行,但不能保证执行顺序

委托语法糖

1.不需要new 委托类型(方法)了,可以直接 +=方法名

2.delegate(参){}匿名方法的出现,可以省去定义方法的步骤,以及lambda表达式,太方便了

3.delegate{},可以省去参数,当你不关心参数时,可以连括号都不用,例如在WinForm this.btn.Click+=delegate{ MessageBox(xxx);};

4.闭包支持,即在匿名方法内部可以访问外部变量

7.属性

属性,get;set;访问器也没什么好说的.在书中,将索引器indexer叫做有参属性

TValue this[TKey key] { [__DynamicallyInvokable] get; [__DynamicallyInvokable] set; }

这是IDictionary<TKey,TValue>接口的索引器

如果有一个IIDictionary<TKey,TValue>实例,dict

默认如果可以用dict["key"],或者dict.Items["key"]

为什么是这个Items呢,在索引器上可以有一个IndexerNameAttribute("ABC"),那样就可以用dict.ABC["key"]来访问,

因为属性,索引器最后都会生成方法,来调用,编译器可以根据这个Attribute来生成方法名称

CLR via C# - 基础拾遗的更多相关文章

  1. C#基础拾遗系列之二:使用ILSpy探索C#7.0新增功能点

    C#基础拾遗系列之二:使用ILSpy探索C#7.0新增功能点   第一部分: C#是一种通用的,类型安全的,面向对象的编程语言.有如下特点: (1)面向对象:c# 是面向对象的范例的一个丰富实现, 它 ...

  2. 基础拾遗------redis详解

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  3. 基础拾遗------webservice详解

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  4. 基础拾遗-----mongoDB操作

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  5. 基础拾遗----RabbitMQ(含封装类库源码)

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  6. 基础拾遗----RabbitMQ

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  7. Java基础拾遗(二)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76358523冷血之心的博客) 马上就要秋招了,新的一轮笔试面试马上 ...

  8. Java基础拾遗(一)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76358391冷血之心的博客) 马上就要秋招了,新的一轮笔试面试马上 ...

  9. Python基础(四) 基础拾遗、数据类型进阶

    一.基础拾遗 (一).变量作用域 外层变量,可以被内层变量直接调用:内层变量,无法被外层变量使用.这种说法在其它语言中适用,在python中除了栈以外,正常的变量作用域,只要执行声明并在内存中存在,该 ...

随机推荐

  1. BULK INSERT如何将大量数据高效地导入SQL Server

    转载自:http://database.51cto.com/art/201108/282631.htm BULK INSERT如何将大量数据高效地导入SQL Server 本文我们详细介绍了BULK ...

  2. 记一次令人发狂的 bug Eclipse 开不开 tomcat 7.0

    改项目,结果发现以前的项目也出了问题,就删除了系统用户下面workplace里的文件夹,结果,eclipse被清空,重新添加项目,发现一堆bug; 最让我崩溃的是,用tomcat 7.0跑项目,反复出 ...

  3. C# 获取当前路径

    // 获取程序的基目录.System.AppDomain.CurrentDomain.BaseDirectory  F:\广告编辑系统新\taxi_edit\taxi_form\bin\Debug\ ...

  4. web api简单验证实现办法

    需要使用WEBAPI,但是有验证问题没解决.后来参考网上文章做了一下DEMO 思路: 就是根据用户的账号在服务端加密一个字符串,然后返回给用户端. 具体: 一个用户编号用于唯一身份识别,密码,一个密钥 ...

  5. POJ1015 动态规划

    POJ1015 问题重述: 在n个候选者中选取m个人进入陪审团.每个候选者获得两项评分:D[j],P[j].求解最佳评审团,使得在每个成员的两项评分和之差 最小的情况下,使得两项评分和之和 最大. 分 ...

  6. 外部主机连接mysql服务器延时严重问题

    1.原因:由于mysql对连接的客户端进行DNS反向解析 2.禁用dns解析,在 /etc/my.cnf 中加入skip-name-resolve 3.反向解析说明: 所谓反向解析是这样的:mysql ...

  7. SQLServer中数据库文件的存放方式,文件和文件组

    我们公司近一年来做了一个CRM系统. 遇到一个问题就是:在插入交流记录的时候速度特别慢.(交流记录数据量大) 后来我们经理采用文件组的方法,将客户交流记录这张表提出来就快很多了 这里有一篇关于文件组的 ...

  8. 观《Terminal》之感

    读书笔记系列链接地址http://www.cnblogs.com/shoufengwei/p/5714661.html.        经人推荐,用了几天时间欣赏了这部斯皮尔伯格导演的电影<Te ...

  9. Java开发工具与程序调试

    开发工具:MyEclipse,Eclipse等. 程序调试:  (1)断点:设置断点是程序调试中必不可少的手段,Java调试器每次遇到程序断点时都会将当前线程挂起,即暂停当前程序的运行.(在Eclip ...

  10. CART剪枝

    与上篇文章中提到的ID3算法和C4.5算法类似,CART算法也是一种决策树分类算法.CART分类回归树算法的本质也是对数据进行分类的,最终数据的表现形式也是以树形的模式展现的,CART与ID3,C4. ...