Programming C#.Classes and Objects.只读字段

只读字段

当字段声明中含有 readonly 修饰符时,该声明所引入的字段为只读字段。给只读字段的直接赋值只能作为声明的组成部分出现,或在同一类中的实例构造函数或静态构造函数中出现。(在这些上下文中,只读字段可以被多次赋值。)准确地说,只在下列上下文中允许对 readonly 字段进行直接赋值:

  • 在用于引入该字段的变量声明符中(通过添加一个变量初始值设定项)。
  • 对于实例字段,在包含字段声明的类的实例构造函数中;对于静态字段,在包含字段声明的类的静态构造函数中。也只有在这些上下文中,将 readonly 字段作为 out 或 ref 参数传递才有效。

在其他任何上下文中,试图对 readonly 字段进行赋值或将它作为 out 或 ref 参数传递都会导致一个编译时错误。

C#常量数据与只读字段

常量数据

C#提供了const关键字来定义常量,如果我们要为应用程序定义逻辑上和某个类或结构相关的一组已知值的话,就非常有用。

假如我们创建一个MyMathClass的工具类,且需要定义一个PI值(假如是3.14),如果不希望别的开发者改变PI值,可以使用如下常量定义PI值:

 1 class MyMathClass
 2 {
 3     //定义为常量数据
 4     public const double PI=3.14;
 5 }
 6 class Program
 7 {
 8     public static void Main(string[] args)
 9     {
10         //注意:因为常量数据是隐式静态的,所以只能直接在类级别上调用(MyMathClass.PI)。
11         Console.WriteLine("PI值是:{0}",MyMathClass.PI);
12
13         //错误!常量数据不能被修改。
14         MyMathClass.PI=3.15;
15         Console.ReadLine();
16     }
17 }

注意:定义常量时必须为常量指定初始值,常量一旦定义就不能修改了。

 1 class MyMathClass
 2 {
 3     //尝试再构造函数中给常量赋值
 4     public const double PI;
 5     public MyMathClass()
 6     {
 7         //错误!
 8         PI=3.14;
 9      }
10 }

在编译时必须知道常量的值!

只读字段

和常量密切联系的概念是只读字段(不要和只读属性混淆哦,只读属性指只有get块的属性)。和常量相似,只读字段不能在赋值后改变。然而,和常量不同,赋值给只读字段可以在运行时决定。因此在构造函数作用域范围内给只读字段赋值是合法的(其他地方不行!)。

 1 class MyMathClass
 2 {
 3     //可以构造函数中为只读字段赋值,其他地方不行!
 4     public readonly double PI;
 5     public MyMathClass()
 6     {
 7         PI=3.14;
 8      }
 9      public void ChangePI()
10      {
11         //错误!
12         PI=3.14;
13       }
14 }

另:只读字段不是隐式静态的,要定义静态只读字段就需要使用static关键字了。

问题:请叙述const与readonly的区别。

const 关键字用于修改字段或局部变量的声明。它指定字段或局部变量的值不能被修改。常数声明引入给定类型的一个或多个常数,开心哦。const数据成员的声明式必须包含初值,且初值必须是一个常量表达式。因为它是在编译时就需要完全评估。const成员可以使用另一个const成员来初始化,前提是两者之间没有循环依赖。readonly在运行期评估赋值,使我们得以在确保“只读访问”的前提下,把object的初始化动作推迟到运行期进行。

readonly 关键字与 const 关键字不同: const 字段只能在该字段的声明中初始化。readonly 字段可以在声明或构造函数中初始化。因此,根据所使用的构造函数,readonly 字段可能具有不同的值。另外,const 字段是编译时常数,而 readonly 字段可用于运行时常数。readonly 只能在声明时或者构造函数里面初始化。

枚举与常量需要注意的一个问题

.net中枚举其实就是数值型的常量,与const类似。当我们在代码中使用枚举代表的数值或者常量时,编译器其实是将该值直接写过来,而不会在运行的时候去读取该值。下面是一个例子:

我们想建立一个类库项目,名称叫ClassLibrary1,再建立一个控制台项目,名称叫ConsoleApplication2,结构如下:

ClassLibrary1项目中Class1中的代码是:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5
 6 namespace ClassLibrary1
 7 {
 8     public class MyClass
 9     {
10         public static string str1 = "str1";
11         public const string str2  = "str2";
12     }
13
14     public enum MyEnum
15     {
16         One   = 1,
17         Two   = 2,
18         Three = 3
19     }
20 }

定义了一个枚举以及一个静态字段、一个常量字段。

ConsoleApplication2项目引用A项目,代码如下:

 1 using System;
 2 using ClassLibrary1;
 3
 4 class Program
 5 {
 6     public static void Main(string[] args)
 7     {
 8         Console.WriteLine((int)MyEnum.One);
 9         Console.WriteLine(MyEnum.One.ToString());
10
11         Console.WriteLine(MyClass.str1);
12         Console.WriteLine(MyClass.str2);
13
14         Console.ReadKey();
15     }
16 }

我们来看看Program类用Reflector工具反编译后的样子:

public class MyClass
{
    // Fields
    public static string str1;
    public const string str2 = "str2";

    // Methods
    static MyClass();
    public MyClass();
}

 注意:这里自动的添加了两个构造函数,一个静态一个非静态。
 1 public static void Main(string[] args)
 2 {
 3     Console.WriteLine(1);
 4     Console.WriteLine(MyEnum.One.ToString());
 5     Console.WriteLine(MyClass.str1);
 6     Console.WriteLine("str2");
 7     Console.ReadKey();
 8 }

编译器将(int)MyEnum.One的值与常量字段str2直接硬编码写到代码中,而不是在运行期再去读取。

这样处理的后果是:如果你修改了A项目中的枚举的排列顺序或者枚举对应的值(或者改变了常量字段str2的值),比如将MyEnum.One的值2,同时不重新编译Test项目,那样运行结果还是不会变的。

时间: 2024-10-15 23:48:14

Programming C#.Classes and Objects.只读字段的相关文章

Programming C#.Classes and Objects.属性

属性是这样的成员:它提供灵活的机制来读取.编写或计算某个私有字段的值. 可以像使用公共数据成员一样使用属性,但实际上它们是称作“访问器”的特殊方法. 这使得可以轻松访问数据,此外还有助于提高方法的安全性和灵活性. 意思是如果我们想封装类的成员变量,但是我们总不能把所有的变量都封装的死死的,不允许外面的任何人看到,这是不合理的. 例如有一个person类,它的属性有姓名.性别.年龄等.我要访问某个对象的性别,或者设置某个对象的性别. 外部的对象要实现,对它的访问,有三种方法: 1.把属性改正pub

Classes as objects

Before understanding metaclasses, you need to master classes in Python. And Python has a very peculiar idea of what classes are, borrowed from the Smalltalk language. 在理解元类之前,你先要掌握Python的类.Python中的类是借鉴了小众语言的特殊的类. In most languages, classes are just p

常量数据与只读字段

常量数据 关键字:const 赋初值后不可改变 隐士静态,在类级别上直接引用 定义常量时,必须指定初始值,在编译时必须知道常量的值,因此,不能在构造函数中进行赋值 只读字段 关键字:readonly 与常量相同,赋初值后不可改变(其实是可以改变的) 与常量不同,不是隐士静态的,在对象级别引用 与常量不同,赋给只读字段的值可以在运行时确定,因此,在构造函数中作用域中进行赋值是合法的(其他地方不行) 1 namespace Test 2 { 3 class Program 4 { 5 static

c#基础知识--常量(const),只读字段(readonly)

1.0:常量 常量被关键字const 所修饰 我们来看看常量的demo class Program { static void Main(string[] args) { const string name = "soaeon"; Console.WriteLine(name); Console.ReadKey(); } } 下面我们看看该demo的反编译结果 哈哈  关于反编译的结果  我们可以看到 定义的  const string  name="soaeon"

属性、构造函数、只读字段、匿名类型

属性:概念指一个方法或一对方法(指get和set方法)在客户端看来,它是一个字段. using System; namespace CodeReview { class Program { static void Main(string[] args) { Console.ReadKey(); } } class Person { //属性声明第一种方式 public string Name { //get不带任何参数,并且必须返回属性声明的类型,这里属性的类型是string get { ret

SAP CRM Genil Text-for-Key-Codes vs SAP C4C只读字段

CRM C4C 这个Assigned To字段UI上显示的是party name, 然而绑定的字段是party ID. 原因是这个UI字段的presentationMode设为DescriptionOnly. 其实际显示的Description的值绑到了/Root/ProcessorFormattedName ProcessorFormattedName在BO的路径:Root-.ProcessorParty-.AddressSnapshot-.DisplayNameSuitableForLogo

C++ Super-FAQ 『Classes and Objects』

类是什么 Type由一组状态和能在多种状态间变换的操作组成: Class提供一组操作和一组数据用于描述type对象的抽象概念. 类接口设计原则 『simplified view』:有意识地隐藏不必要的细节,减少用户出错的几率:『vocabulary of usesrs』 :减少用户学习曲线. 封装是什么 封装是为了阻止未经授权的信息和功能访问. 封装是将代码分为stable和volatile两部分.volatile parts是实现细节,stable parts是接口. Encapsulatio

c#中的classes和objects一些知识【1】

首先我们需要知道面向对象语言(Object-oriented language)的三大特点:封装(Encapulation),继承(Inheritance),多态(Polymorphism). 引言:常见的面向对象语言有C++,JAVA,C#等等.首先先定义一个类,方便大家初步去掌握类到底是怎么写的. public class Students {                                      int sid; int age; //如果不标注private还是pub

Exercise 40: Modules, Classes, And Objects

class Song(object): def __init__(self, lyrics): self.lyrics = lyrics def sing_me_a_song(self): for line in self.lyrics: print line happy_bday = Song(["Happy birthday to you", "I don't want to get sued", "So I'll stop right there&q