[C#基础知识] ReadOnly关键字修饰的变量可以修改,只是不能重新分配

摘要:
当字段声明包含只读修饰符时,声明引入的字段赋值只能作为声明的一部分或在同一类的构造函数中出现。阅读本书后,许多初学者会认为,只读修改的变量将来无法修改。在未来的发展中,ReadOnly的变量永远不会被修改,形成一种心态。这个概念是错误的。开发Microsoft示例和开源代码中使用的扩展的一种方法是使用静态ReadOnly集合容器类,包括默认实现,然后允许用户在开发过程中添加或替换它们。

转自:http://www.cnblogs.com/sujiantao/archive/2011/12/19/2289357.html

MSDN 官方的解释

readonly 关键字是可以在字段上使用的修饰符。当字段声明包括 readonly 修饰符时,该声明引入的字段赋值只能作为声明的一部分出现,或者出现在同一类的构造函数中.
 
很多初学者看完书就会认为,readonly修饰的变量在以后是不能修改的,在以后的开发中从不对ReadOnly的变量进行修改操作,形成思维定势,这个观念是错误的。

首先要明确一点:更改!=重新分配(赋值)

对于简单类型(如int),更改是等于重新赋值,因为默认操作符只有=, 但于对于复杂类型,就不一定了。

例如:

对于class类型,修改其字段属性值。

对于集合类型,增加,移除,清空内容。

我们经常在微软的代码中发现readonly的如下类似的用法:

复制代码
1     public interface IA { }
2     public class A1 : IA { }
3     public class A2 : IA { }

5     public static class AContainer
6     {
7         private static readonly Dictionary<string, IA> Items = new Dictionary<string, IA>();
8         public static Dictionary<string, IA> As{ get { return Items; } }
9     }
复制代码

然后在外部可以修改AContainer

复制代码
 1 class Program
 2     {
 3         static void Main()
 4         {
 5             Console.WriteLine(AContainer.As.Count);
 6             AContainer.As.Add("A1", new A1());
 7             Console.WriteLine(AContainer.As.Count);
 8             AContainer.As.Add("A2", new A2());
 9             Console.WriteLine(AContainer.As.Count);
10             // we can remove all the item of the collection
11             AContainer.As.Clear();
12             Console.WriteLine(AContainer.As.Count);
13             Console.ReadKey();
14         }
15 
16     }
复制代码

输出:

 [C#基础知识] ReadOnly关键字修饰的变量可以修改,只是不能重新分配第5张

结论:

可以在外部(非声明和构造函数)对readonly的变量进行修改内容操作。

微软示例和开源代码中用的一种开发扩展的方式就是使用静态的ReadOnly集合容器类,在其中包括默认的实现,然后允许用户在开发中进行添加或替换。

如MVC3中的 ModelBinderProviders,ViewEngines都是类似的实现。

当然我们还可以通过非常规手段(反射,操作内存)来改变readonly的值。

例如反射

复制代码
 1 using System;
 2 using System.Reflection;
 3 
 4 namespace SOVT
 5 {
 6     public class Foo
 7     {
 8         private readonly int bar;
 9         public Foo(int num) { bar = num; }
10         public int GetBar() { return bar; }
11     }
12 
13     class Program
14     {
15         static void Main()
16         {
17             Foo foo = new Foo(123);
18             Console.WriteLine(foo.GetBar());
19             FieldInfo fieldInfo = typeof(Foo).GetField("bar", BindingFlags.Instance | BindingFlags.NonPublic);
20             if (fieldInfo != null)
21                 fieldInfo.SetValue(foo, 567);
22             Console.WriteLine(foo.GetBar());
23             Console.ReadKey();
24         }
25     }
26 }
复制代码

输出

[C#基础知识] ReadOnly关键字修饰的变量可以修改,只是不能重新分配第8张

免责声明:文章转载自《[C#基础知识] ReadOnly关键字修饰的变量可以修改,只是不能重新分配》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用Java语言开发机器学习框架和参数服务器游戏服务器的架构设计下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Perl中的默认变量$_ 和 @_

默认变量$_ $_表示Perl中的“老地方”,即在没有特殊指定变量的情况下,编译器会默认使用$_变量的内容参与程序运算。 $_还经常使用作为默认匹配空间,在做正则化匹配的时候默认操作的是这个变量。 eg: 1 $_ = "hello world!"; 2 print; print没有指定输出的变量,但是编译器会默认使用$_; 1 foreach(1..10...

Oracle之PL/SQL编程

PL/SQL(ProceduralLanguage/SQL,过程语言/SQL) 是结合了Oracel过程语言和结构化查询语言(SQL)的一种扩展语言。 优点: (1)PL/SQL具有编程语言的特点,它能把一组SQL语句放到一个模块中,使其更具模块化种序的特点。 (2)PL/SQL可以采用过程性语言控制程序的结构。 (3)PL/SQL有自动处理的异常处理机制...

[Unity热更新]tolua# &amp;amp; LuaFramework(一):基础

一、tolua# c#调用lua:LuaState[变量名/函数名] 1.LuaState a.执行lua代码段 DoString(string) DoFile(.lua文件名) Require(.lua文件名(但没有.lua后缀)) b.获取lua函数或者表 LuaFunction func = lua.GetFunction(函数名);      ...

Makefile写法入门心得

Makefile的写法入门心得   Makefile的出现使得编译过程极大地自动化了,省去了很多人工工作,非常方便。这里,小结一下写Makefile的一点小心得。嗯,对了,差点忘了一件事,同一个Makefile在不同的内核版本和Linux发行版本中不一定能发挥一样的作用,别人的Makefile可不见得就适用于自己的机器。 我先简单说一下我自己的机器: Ub...

SQL 存储过程入门(变量)

SQL 存储过程入门(变量)(二)上一篇我们讲到了SQL存储过程的基本定义,怎么创建,使用,这篇就来讲一下变量的使用。 变量分文局部变量和全局变量 局部变量是@开头,全局变量是@@开头,这里我们主要讲局部变量,全局变量我们后面再讲。 在c# 语言中,定义一个变量很简单,例如 int i=0; --定义加赋值。 在sql中,定义一个变量需要关键字DECLAR...

关于OOP(面向对象)

面向对象的程序设计有三大特征: 封装:解决了数据的安全性问题 继承:解决了代码的重用问题 多态:解决了程序的扩展问题 1.类 具有相同特征或者行为的一种抽象。类是具有相同属性和和行为的一组对象的集合。把相同的或相似的对象归为一类的这个过程就是抽象; 可以在定义类时为类添加访问修饰符,对类进行访问权限控制; 对类使用的访问修饰符只有public和缺省两...