博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
readonly, const, static, static readonly 关键字实例说明
阅读量:5235 次
发布时间:2019-06-14

本文共 6244 字,大约阅读时间需要 20 分钟。

      关于 readonly 和 const 的区别,网上已经有很多人撰文作了特别的说明。小G在这里也是参考了网上很多人的文章和MSDN的相关内容才写出的这篇随笔。关于这些修改符的理解,是我个人编程时的经验总结,如有不妥之处,欢迎大家拍砖。

     原本只是想说说 static 的使用场景,但后来觉得这些修饰关键字都相关,索性就都拿出来讲讲,权当积累了。这些关键字是C#语法中非常基础的部分,没错,非常基础。但是我发现在真实项目中,能将这些关键字应用到正确场景中的人并不多,所以我觉得有必要老调重弹,详细说说它们的用法。

    个人认为,其实 readonly 和 const 属于一类关键字,它们只用于修饰字段,决定字段何时被赋值;而 static 则不同,它可以修改字段和方法,决定类型成员是否从属于某一具体的实例,这个我们后面会用实例来作说明。

    1.readonly 关键字

    readonly 关键字是可以在字段上使用的修饰符。 当字段声明包括 readonly 修饰符时,该声明引入的字段赋值只能作为声明的一部分出现,或者出现在同一类的构造函数中。 这是MSDN上对readonly关键字的解释,是不是有点晦涩难懂?嗯,这是MSDN一贯的作风,哈哈。下面我们用实例来作演示,说明 readonly 具体的应用场景。

    “该声明引入的字段赋值只能作为声明的一部分出现”,这句话的意思是,readonly 修改的字段,可以在声明时赋值;“或者出现在同一类的构造函数中”,这句话的意思是,readonly 所修饰的字段,也可以在类的构造函数中赋值。我们以人(People)为例,用代码实例来作说明:

1: void Main()
2: {
3:     Male m=new Male("男");
4:     Female fm=new Female("女");
5:     Console.WriteLine("男士性别:" + m.GetGender);
6:     Console.WriteLine("女士性别:" + fm.GetGender);
7: }
8: 
9: // 人的基类
10: public class People
11: {
12:     private readonly string _gender="男";
13:     public People(){}
14:     public People(string gender)
15:     {
16:         this._gender=gender;
17:     }
18:     public string GetGender
19:     {
20:         get
21:         {
22:             return this._gender;
23:         }
24:     }
25: }
26: // 男性
27: public class Male:People
28: {
29:     public Male(string gender):base(gender)
30:     {
31:     }
32: }
33: // 女性
34: public class Female:People
35: {
36:     public Female(string gender):base(gender)
37:     {
38:     }
39: }

      上面这段代码很好理解,我创建了一个 People 的基类,基类中包含一个 readonly 字段 Gender,即性别,并赋予了默认值“男”(没有别的意思,因为大家通常都叫我们先生嘛(^O^));然后派生出了 Male (男性)和 Female (女性)两个具体的类型,并分别创建了它们的含参构造函数,当然,你可以为这两个派生类创建默认的无参构造,但我肯定你不愿意那样做,因为那样做这个世界就真的大一统了,清一色的光棍啊,吼吼~~~你肯定很难想象没有女孩子这个世界会变成什么样子,所以,老老实实地创建含参构造吧(^_^)。

     这个实例的结果如下:

      男士性别:男

       女士性别:女

     这看起来没什么特别的,下面我们在 People 基类里添加一个测试方法,试图修改 gender 的值,看看会发生什么:

     看到了没?编辑器直接报错了,在构造函数之外的其他方法中修改 readonly 字段是不允许的,这跟人一出生即确定性别是一个道理(当然人类已经逆天了,那部分我们暂且不予理会(-_-)!!!)。

     2.const 关键字

     const 关键字用于修改字段或局部变量的声明。 它指定字段或局部变量的值是常数,不能被修改。   相比之下,这个关键字就容易理解的多了,const 变量在我看来,它就是一个占位符,是C#的设计者为了让大家更好操作常量而允许大家临时定义的一个标记。如果大家用 ILspy 或 Reflector 反编译过.NET程序包,就会发现,const 字段在程序集中全部被替换成了真实的值而不再是变量名。

     仍然用实例来做说明,我们在 People 基类中添加下面这些属性:

1: private const int _numberOfFeet = 2 ;
2: // 脚的数量
3:  public int NumberOfFeet
4: {
5:     get
6:     {
7:         return _numberOfFeet;
8:     }
9: }

      这个属性的作用也很简单,定义了一个常量,用以指示人类脚的数量,并公开一个 NumberOfFeet 属性允许派生类或引用类去获取这个值。我们来尝试给这个属性添加一个 set 写操作器给常量 _numberOfFeet 赋值,看看会发生什么:

      提示已经写得很清楚了,赋值号(即=)左侧必须是个变量、属性或索引器,这也说明 _numberOfFeet 是一个常量,上面这个 set 方法体的内容和 2 = 3 的效果是一样的,这显然不符合C#语法要求,而且也不符合逻辑。const 字段不光在实例方法中不可修改,在构造函数和外部引用中也不能对其进行赋值操作,即 const 字段一经声明,不可更改。这里要注意,const 本身即是包含 static 修饰的,所以 get 方法体内,我没有使用 this._numberOfFeet 来调用它。

      3.static 关键字

      使用 static 修饰符声明属于类型本身而不是属于特定对象的静态成员。 static 修饰符可用于类、字段、方法、属性、运算符、事件和构造函数,但不能用于索引器、析构函数或类以外的类型。 可以这么理解,static 用于指定哪些类型成员是公用的,包括字段、属性、方法、运算符、事件和构造函数;如果一个类被声明为 static,那么此类型不可被实例化,它的所有类型成员都是公用的,也即我们常说的工具类。例如我们经常使用的 Console 类和 Enumerable 类,下面是 Console 类和 Enumerable类 的类型声明:

我们来给 People 类的基类添加一个方法,用于统计人口总数;这个方法不应该从属于某个具体的 People 类实例,无论 Male 还是 Female,只要一出生(创建),世界人口就应该自动递增:

1: void Main()
2: {
3:     Male m=new Male("男");
4:     Console.WriteLine("当前人口总数:" + m.Population);
5:     Female fm=new Female("女");
6:     Console.WriteLine("当前人口总数:" + fm.Population);
7:     // Console.WriteLine("男士性别:" + m.GetGender);
8:     // Console.WriteLine("女士性别:" + fm.GetGender);
9: }
10: 
11: // 人的基类
12: public class People
13: {
14:     private readonly string _gender="男";
15:     public People(){}
16:     public People(string gender)
17:     {
18:         this._gender=gender;
19:     }
20:     public string GetGender
21:     {
22:         get
23:         {
24:             return this._gender;
25:         }
26:     }
27:     private const int _numberOfFeet = 2 ;
28:     // 脚的数量
29:     public int NumberOfFeet
30:     {
31:         get
32:         {
33:             return _numberOfFeet;
34:         }
35:     }
36:
37:     private static int _count = 0;
38:     // 人口递增
39:     public void AddCount()
40:     {
41:         _count++;
42:     }
43:     // 获取人口总数
44:     public virtual int Population
45:     {
46:         get
47:         {
48:             return _count;
49:         }
50:     }
51: }
52: // 男性
53: public class Male:People
54: {
55:     public Male(string gender):base(gender)
56:     {
57:         base.AddCount();
58:     }
59: }
60: // 女性
61: public class Female:People
62: {
63:     public Female(string gender):base(gender)
64:     {
65:         base.AddCount();
66:     }
67: }

这一次,我们在 People 基类中添加了静态字段_count,并添加 AddCount() 方法使其递增,随后修改了 Male 和 Female 的构造函数,调用基类的 AddCount 方法来增加人口数量,程序执行结果如下:

      我们看到只要新增一个 People 的实例,无论是 Male 还是 Female,人口总数都会递增。这其实就是 static 关键字的作用,它使得类型成员可以在多个实例间共用。BTW,来说说误用 static 变量的情形吧。

      我们知道 ASP.NET  应用中,IIS 本身就是使用多线程来响应用户的请求的。来设想这样一个场景,码农在一个页面后台中添加了一个全局的静态变量,好吧,如果他想在多个用户间传递数据,貌似这样也是可行的,只是所有人都只能拿到最后一次赋值的结果。但是,如果他把用户名或是其他验证信息声明为静态变量,而在权限验证之类的地方又刚好引用了这个变量,想想下面会发生什么。当系统管理员访问这个页面时,当前访问这个页面的用户都拥有管理员权限,直至下一用户登录;再极端一点,如果你把这个变量放在了 BasePage 里,那么将迎来另一次大一统,访问派生自 BasePage 页面的用户,都将拥有同最后登录用户的权限验证信息。好了,乡亲们,无论如何,把私密用户信息共享真的是一个很不负责的做法。

      你可能会说我不会犯这样的错误,但这并不代表其他人不会。没错,这是最基本的C#语法,但是我想说,如果我们写了好几年的.NET程序,至今还没搞清楚这些基本概念,抑或是你到现在还不清楚 string 和 StringBuilder 的应用场景一样,这绝对是一件很悲催的事情。

      4. static readonly 关键字

      这实际上并不是一个独立的关键字了,这是前面两个关键字的组合。我们照猫画虎,来定义一下这个关键字的应用场景。readonly 只能用于字段修饰,static 决定字段属于类型而不是特定的对象实例,于是我们可以得出以下定义:

      static readonly 修饰的字段,只能在声明时赋值,或是在静态构造中赋值(关于静态构造的注意事项请参见:《》)。

      static readonly 与 const 的应用场景已十分相似,区别在于,static readonly 修饰的是运行时常量,而 const 修饰的是编译时常量;static readonly 可以用于修饰引用型变量,而 const 修饰的引用型变量只能是 string 或 null(其他引用型变量的构造函数初始化是在运行时,而非编译时)。

     下面是微软的 Color 类的构造示例,演示了 static readonly 的具体应用场景:

1: public class Color
2: {
3:     public static readonly Color Black = new Color(0, 0, 0);
4:     public static readonly Color White = new Color(255, 255, 255);
5:     public static readonly Color Red = new Color(255, 0, 0);
6:     public static readonly Color Green = new Color(0, 255, 0);
7:     public static readonly Color Blue = new Color(0, 0, 255);
8:     private byte red, green, blue;
9: 
10:     public Color(byte r, byte g, byte b)
11:     {
12:         red = r;
13:         green = g;
14:         blue = b;
15:     }
16: }

     这是特别说明一下,string 是一个非常特殊的引用型类型,详细的解释,请参见:《》。

转载于:https://www.cnblogs.com/gb2013/archive/2012/11/28/2792699.html

你可能感兴趣的文章
主流CAD菜单开发
查看>>
Consul服务器配置
查看>>
数据库自增实现
查看>>
死锁与多线程
查看>>
HttpPost请求将json作为请求体传入的简单处理方法
查看>>
TortoiseSVN文档
查看>>
Python从零开始 day5
查看>>
4-5 颜色反转
查看>>
4-14 图像特效小结
查看>>
len=in.read(b,0,len)和len=in.read(b)的区别
查看>>
Python入门 五、学着机器思考
查看>>
js高级---本地对象、内置对象、宿主对象
查看>>
get与post请求
查看>>
基于反射技术汽车电子产品(ECU, SCM, 开关等)测试平台软件 (二)
查看>>
纪念日倒计时程序
查看>>
Python读取PDF文档
查看>>
leetcode-Game of Life-289
查看>>
(转)浅谈移动操作系统的跨应用通信机制
查看>>
常用的Hql语句
查看>>
可变字符串
查看>>