原文:[CLR via C#]7. 常量和字段

7.1 常量

  常量(constant)是一个特殊的值,它是一个从不变化的值。

  在定义常量时,它的值必须在编译时确定。确定之后,编译器将常量的值保存到程序集的元数据中。这就意味着只能为编译器认定的基元类型定义常量。
 
  C#是允许定义一个非基元类型的常量变量(constant variable),但这个值应设为null。
public sealed class SomeType {
//SomeType不是基元类型,但C#允许定义
//值为null的这种类型的一个常量变量
public const SomeType Empty = null;
}

  由于常量的值从不变化,所以常量总是被视为类型定义的一部分。所以,常量是静态成员,而不是实例成员。定义常量将导致创建元数据。

  代码引用一个常量符号时,编译器会在定义常量的程序集的元数据中查找该符号,提取常量的值,并将值嵌入生成的IL代码中。由于常量的值直接嵌入代码中,所以运行时不需要为常量额外分配内存。
  除此之外,不能获取常量的地址,也不能以传递引用的方式传递常量。
 
  基于上一条,假如A程序集只依赖于B程序集中的常量,那么编译后,即使删除B程序集,A程序集也不会受到影响,也是能找到B程序集中定义的常量值。
 
7.2 字段
 
  字段(field)是一种数据成员,其中容纳了一个值类型的实例或者对一个引用类型的引用。
 
  下表总结了应用于字段的修饰符:
CLR术语 C#术语 说明
Static static 这种字段是类型状态的一部分,而不是对象状态的一部分
Instance 默认 这种字段与类型的一个实例关联,而不是与类型本身关联
InitOnly readOnly 这种字段只能由一个构造器方法中的代码写入
Volatile volatile 看到访问这种字段的代码,编译器、CLR或硬件就不会执行一些"线程不安全"的优化措施
   
  CLR支持类型(静态)字段和实例(非静态)字段。对于类型字段,用于容纳字段数据的动态内存是在类型对象中分配的,而类型对象是在类型加载到一个AppDomain时创建的。什么时候要将类型加载到一个AppDimain中呢?通常是在引用了该类型的任何方法首次进行JIT编译的时候。
 
  对于实例字段,用于容纳字段数据的动态内存则是在构造类型的一个实例时分配的。
 
  由于字段存储在动态内存中,所有它们的值在运行时才能获取。字段还解决了常量存在的版本控制的问题。此外,字段可以是任何数据类型。
 
  CLR支持readonly字段和read/write字段。大多数字段是read/write字段,这意味着在代码执行过程中,字段可以多次改变。但是,readonly字段只能在一个构造器方法中写入(在这有人会有疑问,我可以直接定义readonly的值啊?比如private readonly int ss = 123;不必从构造器方法中写入?这问题,以后会提到)。注意,可以利用反射来修改readonly字段。
 
  下面演示了如何定义一个与类型本身关联的readonly静态字段和读/写静态字段。另外还定义了read/wite静态字段,以及readonly和read/write实例字段。
public sealed class SomeType {
// 这是一个静态readonly字段:在运行时对Random类进行初始化
// 它的值会被计算并存储到内存中
public static readonly Random s_random = new Random(); // 这是一个静态read/write字段
private static Int32 s_numberOfWrites = ; // 这是一个实例readonly字段
public readonly String Pathname = "Untitled"; // 这是一个实例read/write字段
private System.IO.FileStream m_fs; public SomeType(String pathname) {
// 这行修改只读字段Pathname
// 由于是在构造其中,所有可以进行修改
this.Pathname = pathname;
} public String DoSomething() {
// 该行读写静态read/write字段
s_numberOfWrites = s_numberOfWrites + ; // 这行读取readonly实例字段
return Pathname;
}
}

  在上述代码中,许多字段都是内联初始化的。C#允许使用内联初始化语法来初始化类的常量、read/write字段和readonly字段。在后面会讲到,C#实际是在构造器中对字段进行初始化的,字段的内联初始化只是一种语法上的简化而已。另外,在C#中使用内联初始化,有一些性能问题需要考虑,这些以后会着重讲解。

  注意,当某个字段是引用类型,并且该字段标记为readonly时,那么不可改变的引用,而非字段引用的值。
internal static class ReadOnlyReferences {
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[] = 'X';
AType.InvalidChars[] = 'Y';
AType.InvalidChars[] = 'Z'; // 下一行代码是非法的,无法通过编译
// 因为不能让InvalidChars 引用别的什么东西
//AType.InvalidChars = new Char[] { 'X', 'Y', 'Z' };
}
}
}

[CLR via C#]7. 常量和字段的更多相关文章

  1. CLR via C#深解笔记三 - 基元类型、引用类型和值类型 | 类型和成员基础 | 常量和字段

    编程语言的基元类型   某些数据类型如此常用,以至于许多编译器允许代码以简化的语法来操纵它们. System.Int32 a = new System.Int32();  // a = 0 a = 1 ...

  2. CLR类型设计之类型之常量和字段

             前言 孔子说:温故而知新,可以为师矣.所以对于学习过的知识要多复习,并且每一次复习都要尽可能的去扩展,而不是书本上的几句理论知识.很多人都喜欢分享自己的学习内容,记录下生活的点点滴滴 ...

  3. clr via c#读书笔记五:常量和字段

    1.常量是值从不变化的符号.只能定义编译器识别的基元类型的常量.如:Boolean,Char,Byte,SByte,Int16,UInt16,Int32,UInt32,Int64,Single,Dou ...

  4. [Clr via C#读书笔记]Cp7常量和字段

    Cp7常量和字段 常量 常量在编译的时候必须确定,只能一编译器认定的基元类型.被视为静态,不需要static:直接嵌入IL中: 区别ReadOnly 只能在构造的时候初始化,内联初始化. 字段 数据成 ...

  5. C#常量和字段以及各种方法的语法总结

    目录 一. 常量和字段.... 1 1. 常量.... 1 2.字段.... 1 二.方法.... 2 1.实例构造器和类(引用类型).... 2 2.实例构造器和结构(值类型).... 2 3.类型 ...

  6. C#基础之类型和成员基础以及常量、字段、属性

    首先吐糟一下今天杭州的天气,真是太热了!虽然没有妹子跟我约会,但宅在方寸大的窝里,也是烦躁不已! 接上一篇<C#基础之基本类型> 类型和成员基础 在C#中,一个类型内部可以定义多种成员:常 ...

  7. 常量,字段,构造方法 调试 ms 源代码 一个C#二维码图片识别的Demo 近期ASP.NET问题汇总及对应的解决办法 c# chart控件柱状图,改变柱子宽度 使用C#创建Windows服务 C#服务端判断客户端socket是否已断开的方法 线程 线程池 Task .NET 单元测试的利剑——模拟框架Moq

    常量,字段,构造方法   常量 1.什么是常量 ​ 常量是值从不变化的符号,在编译之前值就必须确定.编译后,常量值会保存到程序集元数据中.所以,常量必须是编译器识别的基元类型的常量,如:Boolean ...

  8. C#学习笔记——常量、字段以及事件

    一 常量与字段 (一) 常量 常量总是被视为静态成员,而不是实例成员.定义常量将导致创建元数据.代码引用一个常量时,编译器会在定义常量的程序集的元数据中查找该符号,提取常量的值,并将值嵌入IL中.由于 ...

  9. [一]class 文件浅析 .class文件格式详解 字段方法属性常量池字段 class文件属性表 数据类型 数据结构

    前言概述  本文旨在讲解class文件的整体结构信息,阅读本文后应该可以完整的了解class文件的格式以及各个部分的逻辑组成含义   class文件包含了java虚拟机指令集 和  符号表   以及若 ...

随机推荐

  1. freemarker错误九

    1.错误叙述性说明 五月 30, 2014 11:52:04 下午 freemarker.log.JDK14LoggerFactory$JDK14Logger error 严重: Template p ...

  2. Oracle 六闪回技术,flashback

    Flashback 技术基于Undo segment基于内容的, 因此,限制UNDO_RETENTON参数. 要使用flashback 特征,您必须启用自己主动撤销管理表空间. 在Oracle 11g ...

  3. Tomcat—怎样在Tomcat Webserver下部署Web项目

            总结一下怎样在Tomcat Webserver下部署Web项目:

  4. SQL Server高可用——日志传送(4-2)——部署

    原文:SQL Server高可用--日志传送(4-2)--部署 前文再续,书接上一回.本章演示一下日志传送的具体过程 准备工作: 由于时间关系,已经装好了3台虚拟机,且同在一个域里面: SQL01:主 ...

  5. 13 于C#如何获得在IP住址

    首先,需要加入一个命名空间 using System.Net.NetworkInformation; using System.Net.Sockets; 以下是具体代码 GetPrivateIP(); ...

  6. net开源cms系统

    .net开源cms系统推荐 内容目录: 提起开源cms,大家第一想到的是php的cms,因为php开源的最早,也最为用户和站长们认可,随着各大cms系统的功能的不断完善和各式各样的开源cms的出现,. ...

  7. STL源代码分析--迭代摘要、迭代器失效汇总

    Vector 1.内部数据结构:连续存储,比如数组. 2.随机訪问每一个元素,所须要的时间为常量. 3.在末尾添加或删除元素所需时间与元素数目无关,在中间或开头添加或删除元素所需时间随元素数目呈线性变 ...

  8. sun.misc.BASE64Encoder我找不到jar一揽子解决方案

    1.合适的项目 --> 属性(Properties) --> java bulid path --> Libraries -> jre System Library(点加号在前 ...

  9. Maven构建Hadoop

    Maven构建Hadoop工程 阅读目录 序 Maven 安装 构建 示例下载 系列索引 序 上一篇,我们编写了第一个MapReduce,并且成功的运行了Job,Hadoop1.x是通过ant来管理工 ...

  10. 网络语音视频技术浅议 Visual Studio 2010(转)

    我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...