关于C#中readonly的一点小研究

可能园子里有不少文章已经说明了这个问题了,但是我在这里写这篇博客只是写写自己的一些体会,也权当是整理归纳,高手莫见笑。

===============正文分割线==================

现在正在学《编译原理》课,老师让我们根据给出的语言定义自己开发一个编译器,本人对C#还是比较熟悉的所以优先选择C#作为开发工具。本人用的是VS2012配Resharper,这是一个很好用的代码分析及重构的工具,简化了不少工作,但也有些问题一直都搞不懂。例如,在这个类中,Resharper一直提示“将字段设为readonly”。

从字面上看,readonly即“只读”的,这就造成了误解,让我误以为readonly的变量是不可编辑的,因此一直没敢用这条建议。

但是既然这么提示了,总应该是有道理的。因此我就查了很多资料,包括在园子里提问,在加上自己的一点研究,终于算是搞懂了意思。

例如我们这里有一个类

    class TestClass2
    {
        private int someValue;

        public void ChangeValue(int newValue)
        {
            someValue = newValue;
        }

        public int ShowValue()
        {
            return someValue;
        }
    }

而在另一个类中使用它

    class TestClass
    {
        private readonly TestClass2 tc; // 注意此处tc是readonly的

        public TestClass()
        {
            tc = new TestClass2();
        }

        public void ChangeTCValue(int value)
        {
            tc.ChangeValue(value);
        }

        public void Show()
        {
            Console.WriteLine("{0}", tc.ShowValue());
        }
    }

我们看到虽然tc这个字段是readonly的,但是可以使用方法来改变tc中someValue的值。似乎这个“只读”失去了意义,因为可以修改它的值的话还叫什么“只读”呢?

非也!

从上面的代码中我们可以看到,tc的类型是TestClass2,是一个引用类型。而引用类型是必须用new关键字为它分配了一块内存以后它才能在后续代码中工作的。也就是说,tc这个变量仅仅是一块内存地址罢了。图示如下:

也就是说,这里的“readonly” tc只是无法再重新更改它的引用,但它所引用对象的属性是可以改变的。

那么为什么不用const呢?还是因为tc是引用,是动态分配内存的,不可能在编译阶段就确定它的地址,这点和值类型(包括string)是完全不一样的。

综上所述,可以得出结论:readonly修饰的字段,其初始化仅是固定了其引用(地址不能修改),但它引用的对象的属性是可以更改的。

当然,这里的“地址不能修改”指的是在代码中不能再对readonly变量进行再赋值,实际运行情况中可能会遇到GC或反射改变内存的情况。但是在本文所说的环境下不必考虑。(2013-9-27 14:30修改)

所以,大胆放心的用readonly吧,这样还可以防止不必要的再赋值,保证了这个对象的安全性。

PS:这样的两个类之间的关系事实上就是UML中的组合关系

转载于:https://www.cnblogs.com/ryuasuka/p/3342282.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#readonly是一个关键字,用于声明只读字段。只读字段是在声明时或构造函数初始化,并且不能在其他地方再次赋值。与const关键字不同,readonly字段可以在字段声明和任何构造函数多次分配不同的值。这使得readonly字段可以在运行时根据需要进行初始化。 例如,可以使用readonly关键字声明一个只读字段,并在构造函数初始化它: ``` public class ReadOnlyDemo { private readonly string _code = "empty string"; public ReadOnlyDemo(string code) { _code = code; } public string GetCode() { return _code; } } ``` 在上面的示例,_code字段是只读的,它在构造函数被初始化,并且不能在其他方法再次赋值。 另外,readonly字段也可以用于运行时常量。这意味着它们可以在运行时被赋值,并且在整个程序的执行过程保持不变。这与编译时常量(const)不同,后者在编译时被赋值并且在整个程序的执行过程保持不变。 例如,下面的示例展示了如何在构造函数初始化只读字段,并在运行时保持不变: ``` public static readonly uint timeStamp = (uint)DateTime.Now.Ticks; ``` 在上面的示例,timeStamp字段是只读的,并且在声明时被初始化为当前时间的刻度数。由于它是只读的,它的值在整个程序的执行过程保持不变。 总结起来,C#readonly关键字用于声明只读字段,这些字段在声明时或构造函数初始化,并且不能在其他地方再次赋值。它们可以在运行时根据需要进行初始化,并且可以用于运行时常量。 #### 引用[.reference_title] - *1* *2* [一看就懂——C#readonly关键字](https://blog.csdn.net/CrazyRock98/article/details/106490654)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C#——关键字:readonly](https://blog.csdn.net/weixin_43945471/article/details/112473546)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值