zoukankan      html  css  js  c++  java
  • CLR via C#

    编译器开关设置 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如下

     1 [SecuritySafeCritical, __DynamicallyInvokable]
     2 public override bool Equals(object obj)
     3 {
     4     if (obj == null)
     5     {
     6         return false;
     7     }
     8     RuntimeType type = (RuntimeType) base.GetType();
     9     RuntimeType type2 = (RuntimeType) obj.GetType();
    10     if (type2 != type)
    11     {
    12         return false;
    13     }
    14     object a = this;
    15     if (CanCompareBits(this))
    16     {
    17         return FastEqualsCheck(a, obj);
    18     }
    19     FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    20     for (int i = 0; i < fields.Length; i++)
    21     {
    22         object obj3 = ((RtFieldInfo) fields[i]).UnsafeGetValue(a);
    23         object obj4 = ((RtFieldInfo) fields[i]).UnsafeGetValue(obj);
    24         if (obj3 == null)
    25         {
    26             if (obj4 != null)
    27             {
    28                 return false;
    29             }
    30         }
    31         else if (!obj3.Equals(obj4))
    32         {
    33             return false;
    34         }
    35     }
    36     return true;
    37 }
    38 
    39  
    40 
    41  
    View Code

    通过比较值,我们来看看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来生成方法名称

  • 相关阅读:
    字节对齐方法
    以太网帧、IP报文格式
    单光纤udp通信
    错误笔记(1)——关于克隆虚拟机引发的后续问题
    linux 查看目录名称的方法
    rpm方式安装MySQL-5.6
    克隆虚拟机后修改MAC地址
    安卓反编译一些记录
    mysql日志
    Linux文件监控工具——inotify-tools
  • 原文地址:https://www.cnblogs.com/magicdawn/p/3602313.html
Copyright © 2011-2022 走看看