zoukankan      html  css  js  c++  java
  • static const readonly 究竟是什么?

    参考资料:
    《C# 7.0 本质论》
    B站杨旭C#教程:https://www.bilibili.com/video/BV1k4411H7aM?p=4

    下面的一部分内容是来自《C# 7.0 本质论》,还有一部分是我直接把杨旭C#教程的PPT手打了一遍,为了促进我的思考。建议朋友们直接去看他的教程,还辅以他的一些讲解,更加易懂。

    什么是static

    C#没有全局变量或全局函数,在C#中与全局字段或函数等价的是静态字段或方法。“全局变量/函数”和“C#静态字段/方法”在功能上没有差异,只是静态字段/方法可包含访问修饰符,比如private,从而限制访问并提供更好的封装。

    什么是静态字段

    • 使用static关键字定义能由同一个类的多个实例共享的数据
    • 和实例字段(非静态字段)一样,静态字段也可在声明时初始化。
    • 和实例字段不同,未初始化的静态字段将获得默认值(0,null,false等),所以没有显式赋值的静态字段也是可以访问的
    • 变量的作用域是可以不加限定来引用的程序代码区域
    • 静态字段的作用域是类(及其任何派生类)

    注意,在设计对象时,程序员要考虑字段和方法应声明为静态还是基于实例。

    • 将不需要访问任何实例数据的方法声明为静态方法
    • 将需要访问实例数据的方法(实例不作为参数传递)声明为实例方法
    • 静态字段主要存储对应于类的数据,比如新实例的默认值或者已创建实例个数
    • 实例字段主要存储和对象关联的数据

    例如,我们需要记录到现在一共创建过多少个该对象的实例,就可以用静态字段。

    什么是const(常量)

    • 一个值不可以改变的静态字段
    • 在编译时值就已经定下来了
    • 任何使用常量的地方,编译器都会把这个常量替换为它的值
    • 常量的类型可以是内置的数值类型、bool、char、string或enum
    • 使用const关键字声明,生命的同时必须使用具体的值来对其初始化

    示例:

    public class Test
    {
        public const string Message = "Hello World!";
    }
    

    设计规范:

    • 要为永远不变的值使用常量字段
    • 不要为将来会发生变化的值使用常量字段

    什么是readonly

    • 和const不同,readonly修饰符只能用于字段,不能用于局部变量
    • 它指出字段值只能从构造函数中更改,或在声明时通过初始化器指定

    原来只读(readonly)的字段是可以修改的,不过只能从构造函数中更改,或在声明时通过初始化器指定。const的不可以修改。

    常量(const)与静态只读字段的区别

    • 常量比静态只读字段更严格:
      • 可使用的类型(const更少一些)
      • 字段初始化的语义上
    • 常量是在编译时进行值的估算

    QQ截图20200614114054.png

    常量编译时直接把具体的值带进来了,运行时直接运行具体的值。

    注意:
    当值有可能改变,并且与需要暴露给其它Assembly(程序集)的时候,静态只读(static、readonly)字段是相对较好的选择。

    public const decimal ProgramVersion = 2.3;
    

    如果Y Assembly引用了X Assembly并且使用了这个常量,那么在编译的时候,2.3这个值就会被固化于Y Assembly里。这意味着,如果后来X重编译了,这个常量变成了2.4或其它值,如果Y不重新编译的话,Y将仍然使用2.3这个值,直到Y被重新编译,它的值才会变成2.4.静态只读字段就会避免这个问题的发生

    另外,方法可以有本地的常量:

    static void Main()
    {
        const double twoPI = 2 * System.Math.PI;
        ...
    }
    

    什么是静态构造函数

    • 静态构造函数,每个类执行一次

    • 非静态构造函数,每个实例执行一次

    • 一个类型只能定义一个静态构造函数

      • 必须无参
      • 方法名与类型一致
      class Test
      {
          static Test() { Console.WriteLine("Type Initialized"); }
      }
      
    • 在类型使用之前的一瞬间,编译器会自动调用类型的静态构造函数:

      • 实例化一个类型
      • 访问类型的一个静态成员
    • 只允许使用 unsafe 和 extern 修饰符

    注意,如果静态构造函数抛出了未处理的异常,那么这个类型在该程序的剩余生命周期内将无法使用了。

    静态字段和静态构造函数的初始化顺序

    • 静态字段的初始化器在静态构造函数被调用之前的一瞬间运行
    • 如果类型没有静态构造函数,那么静态字段初始化器在类型被使用之前的一瞬间执行,或者在运行时突发奇想的时候执行
    • 静态字段的初始化顺序与它们的声明顺序一致
    class Foo
    {
        public static int X = Y; // 0
        public static int Y = 3; // 3
    }
    

    例子:

    class Program
    {
        static void Main() { Console.WriteLine(Foo.X); } // 3
    }
    
    class Foo
    {
        public static Foo Instance = new Foo();
        public static int X = 3;
    
        Foo() { Console.WriteLine(X); } // 0 
    }
    

    Program中,使用了类型Foo,在类型使用之前的一瞬间,初始化了Foo类中第二行的静态字段X,所以Program中输出3。

    Foo中,静态字段的初始化顺序使按照它们声明的顺序决定的,即先初始化Instance,new Foo(),直接调用了该构造函数,此时X还未被初始化为3,所以输出X的值为int型的默认值 0。

    什么是静态属性

    属性也可声明为static,使用静态属性几乎肯定比使用公共静态字段好,因为公共静态字段在任何地方都能调用,而静态属性至少提供了一定程度的封装。

    什么是静态类

    • 类也可以是静态的
    • 其成员必须全是静态的
    • 不可以有子类
    • 例如
      • System.Console
      • System.Math

    什么是Finalizer(终结器或析构函数)

    • Finalizer是class专有的一种方法
    • 在GC回收未引用对象的内存之前运行
    • 其实就是对object的Finalize()方法重写的一种语法
    class Class1
    {
        ~Class1()
        {
            ...
        }
    }
    

    这个东西我学C++的时候好像翻译成析构函数,在开发中基本没用过。

    感受

    static和const是自从我开始学编程以来就一直困扰着我的东西,因为平常不怎么用,就一直没去研究。现在我依旧不是很理解它们。希望以后可以随着我的编程经验的增加,来慢慢理解它们。

  • 相关阅读:
    使用IDEA工具配置和运行vue项目(详细其中的坑)
    VSCode打开已有vuejs项目
    vue中遇到的问题:Error: Cannot find module 'chalk'
    Qt源码分析之信号和槽机制(QMetaObject是一个内部struct)
    “ping”命令的原理就是向对方主机发送UDP数据包,HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”
    程序员保值的4个秘密(要当语言和框架方面的专家,高难技术,业务,算法,产品意识与思维(把细节做好))
    C++ 多线程阻塞 (多线程同步)(MsgWaitForMultipleObjects)(连着消息一起控制,牛)
    兴趣与坚持:程序员从初级到中级10个秘诀(要学另一门语言,学会搜索,找到真正令你着迷的东西,不能为工资、要真正享受工作)
    Spring MVC 数据回显
    内存问题检测神器:Valgrind
  • 原文地址:https://www.cnblogs.com/Kit-L/p/13128742.html
Copyright © 2011-2022 走看看