zoukankan      html  css  js  c++  java
  • CLR笔记:6.类型和成员基础

    1.Class的可见性有public和internal两种,public对所有程序集都可见,internal仅对其所在的程序集可见。默认是internal的。

    2.友元程序集,
        使用friend assembly可以实现单元测试,而不使用反射技术。
        书上讲的是按照命令行编译。

        我测试用的是vs2005的solution,如下:


    3.成员的可访问性
        成员默认是private的,接口类型的成员都是public的。
        子类重写父类的成员时,原始成员与重写成员要有相同的可访问性——C#的约束;CLR的约束是,重写成员的可访问性不能更低。
        
        CLR和C#是不一样的,如表:

    CLR术语 C#术语
    Private private
    Family protected
    Family and Assembly 不支持
    Assembly internal
    Family or Assembly protected internal
    Public public

    4.静态类
    static只能用于class,不能用于struct,因为CLR要求值必须实例化,而且不能控制实例化过程。
    C#对静态类的约束:
        静态类必须直接从System.Object派生
        静态类不能实现任何接口
        静态类只能定义静态成员:字段,方法,属性,事件
        静态类不能用作:字段,方法,参数,局部变量。
    在MSIL中,不会为静态类生成ctor,会将其标记为abstract和sealed

    5.部分类
        CLR不支持partial,只是C#的语法。所以某个类型的源码必须使用同一种编程语言

    6.组件,多态和版本控制
    .NET版本号2.7.1.34,包含4个部分:主版本号,次版本号,内部版本号,修订版本号。
        修订版本,向后兼容,改变内部/修订版本号;
        发布新版本,不向后兼容,改变主/次版本号。
    多态中,子类重写父类的虚方法,会引起版本控制问题,即父类发生改变,其版本低于子类版本,会导致子类行为变化。
    C# 5个用于 类/类成员 的 影响组件版本控制 的 关键字:
        abstract:用于类/类成员
        virtual和override:用于成员
        sealed:用于类/类成员。用于成员时,仅用于重写了虚方法的方法。
        new,用于类/类成员/常量/字段

    C#调用虚方法:
        CLR允许类中定义多个"同名方法",仅仅是返回类型不同,IL允许这样做;C#不允许,忽略返回值的类型,相应的用"转换操作符"实现IL中的"同名方法"。
        
        调用方法相应的MSIL:
            一个是call,用来调用静态方法,实例方法和虚方法。必须要指定调用方法的类型(对于静态方法)或者对象(对于实例方法/虚方法),如果在该类型/对象中找不到该方法,会检查其基类来匹配方法。
            另一个是callvirt,用来调用实例方法和虚方法,不能用于调用静态方法。必须要指定调用方法的实例对象,如果这个对象为null,会抛出NullReferenceException异常,这意味着每次调用前都会有额外的null检查,从而比调用call慢一些。
            如下代码所示:
        public sealed class Program
        
    {
            
    public Int32 GetFive()
            
    {
                
    return 5;
            }


            
    public static void Main()
            
    {
                Program p 
    = null;
                Int32 x 
    = p.GetFive();  //在C#中,使用callvirt,会抛出NullReferenceException异常
            }

        }
         
            在C#编译器中,使用callvirt调用所有实例方法(包括虚方法),使用call调用所有静态方法。对于其他的编译器,这一点不能保证,所以在虚方法和非虚方法之间改动而不重新编译,会产生无法预测的问题。
            C#使用call而不用callvirt调用虚方法的特例:ToString,见下:
        internal class SomeClass
        
    {
            
    public override string ToString()
            
    {
                
    return base.ToString();
            }

        }
            这时候,生成call的IL代码。因为如果使用callvirt,意味着这时一个虚方法,从而递归执行该方法,直到AppDomain的堆栈溢出。

            在调用值类型定义的方法时,使用call。这是因为,首先,值类型是密封的,从而不存在虚方法;另外,值类型永远不会为null,所以永远不会抛出NullReferenceException异常;再者,如果使用callvirt,就要使用装箱机制,性能会有极大影响。
            
            在设计class的过程中,要尽量少定义虚方法。取代办法:可以定义一组重载方法,经其中最复杂的方法虚拟化,而将所有有用的重载非虚拟化,示例如下:
        public class Set
        
    {
            
    private Int32 m_length = 0;

            
    //这个有用的重载是非虚拟的
            public Int32 Find(Object value)
            
    {
                
    return Find(value, 0, m_length);
            }


            
    //这个有用的重载是非虚拟的
            public Int32 Find(Object value, Int32 startIndex)
            
    {
                
    return Find(value, 0, m_length - startIndex);
            }


            
    //功能最丰富的方法是虚拟的,可以被重写
            public Int32 Find(Object value, Int32 startIndex, Int32 endIndex)
            
    {
                .
    //具体实现
            }

        }

        sealed密闭类尽量使用。将sealed改为非密闭的容易,反之困难;性能也快,因为sealed一定是非虚拟的,从而编译器不用考虑其派生类,而虚方法的性能不如非虚方法;因为密闭了,所以安全性和可预测性也就高。

        子类中有父类的方法,会警告,不会报错。这时要使用new关键字,告诉CLR,新旧方法没有任何关系。
  • 相关阅读:
    排序--插入排序(Insertion Sort)Java实现
    汉诺塔--递归和非递归 Java实现
    关于mysql使用utf8编码在cmd窗口无法添加中文数据的问题以及解决 方法二
    mysql在cmd中查询到的汉字乱码问题解决 方法一
    mysql绿色版安装以及遇到的问题
    关于按下回车键自动提交表单问题解决
    获取iframe引入页面内的元素
    ORACLE 中如何截取到时间的年月日中的年、月、日
    Jboss 7配置日志
    java中将科学技术发转为正常数据
  • 原文地址:https://www.cnblogs.com/Jax/p/890812.html
Copyright © 2011-2022 走看看