第七章 常量和字段

常量:

  • 常量是值从不变化的符号,它的值必须能在编译时就确定,确定以后编译器将其值保存到程序集元数据中。

  • 常量总是被视为静态成员。

  • 代码引用时,会在元数据中查找常量符号,提取其对应的值,然后将值嵌入到生成的IL代码中。这样在运行时就不需要为其分配内存

  • 只有在确定了一个符号的值从不变化以后,才应该定义一个常量。

  • 如果希望在运行时从一个程序集中提取另一个程序集中的值,就不应该使用常量,而应该使用readonly字段。

字段:

  • 字段是一种数据成员,其中内容可分为以下两种:
  1. 一个值类型的实例。
  2. 对一个引用类型的引用。
  • 字段大致分为以下两种:
  1. 类型字段:其容纳数据所需的动态内存是在类型对象中分配的。
  2. 实例字段:其容纳数据所需的动态内存是在构造类型的实例时分配的。
  • 字段可用的修饰符:
  1. static :表明修饰的字段是类型状态的一部分,而不是对象状态的一部分。
  2. readonly :表明修饰的字段只能由一个构造器方法中的代码写入。(构造器方法只能调用一次,即对象首次创建时(实例字段)或是对类进行初始化时(类型字段)
    (注:除了构造器,还可以利用反射来修改readonly字段。)
相对应的代码演示:
public sealed class SomeType
{
  //这是一个静态 readonly 字段;在运行时对这个类进行初始化时,它的值会被计算并存储到内存中。
  public static readonly Random s_random = new Random();

  //这是一个静态 read/write 字段
  private static Int32 s_numberOfWrites = 0;

  //这是一个实例 readonly 字段
  private System.IO.FileStream m_fs;

  public SomeType(String pathname)
  {
    //改行修改只读字段(readonly修饰的)pathname,在构造器中可以这么做。
    this.Pathname = pathname;
  }
  
  public String DoSomething()
  {
    //该行读写静态 read/write 字段
    s_numberOfWrites = s_numberOfWrites + 1;
     
    //该行读取 readonly 实例字段
    return Pathname;
  }
}

(在上述代码中,存在如:private static Int32 s_numberOfWrites = 0; 这种直接在类型定义中(构造器方法外)为常量和字段进行初始化的操作,被称为内联初始化。)

内联初始化:指在代码中直接赋值来初始化,而不是将对构造器的调用写出来。

其实质还是在构造器中进行初始化,只是一种形式上的简便化语法,是C#语言提供的 语法糖

readonly字段如果是引用类型,不可改变的是引用,而非字段引用的对象。(类似于C++中的const指针)其演示代码如下:
public sealed class AType
{
  //InvalidChars 总是引用同一个数组对象
  public static readonly Char[] InvalidChars = new Char[] {'A','B','C'};
}

public sealed class AnotherType
{
  public static void M()
  {
    //下面三行代码是合法的,可通过编译,并可成功修改 InvalidChars 数组中的字符
    AType.InvalidChars[0] = 'X';
    AType.InvalidChars[1] = 'Y';
    AType.InvalidChars[2] = 'Z';

    //下一行代码是非法的,无法通过编译的,因为不能让 InvalidChars 引用别的什么东西。
    AType.InvalidChars = new Char[] {'X','Y','Z'};
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容