前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >c# readonly

c# readonly

作者头像
JusterZhu
发布2023-10-25 10:52:08
1850
发布2023-10-25 10:52:08
举报
文章被收录于专栏:JusterZhuJusterZhu

在C#中,readonly特性用于声明一个只读字段。一个只读字段可以在声明时或在构造函数内部进行初始化,一旦被赋予了初始值,它就不能被改变。

使用

下面是使用 readonly 特性的基本语法:

代码语言:javascript
复制
public readonly int MyField;

您也可以在构造函数中初始化只读字段,如下所示:

代码语言:javascript
复制
public class MyClass
{
    public readonly int MyField;

    public MyClass(int value)
    {
        MyField = value;
    }
}

注意事项

  • 只读字段只能在声明或者构造函数中赋值。
  • 只读字段的值不能更改,相当于常量,但常量在编译时需要初始化,只读字段则在运行时初始化。
  • 只读字段可以具有不同的值,取决于所用的构造函数来创建对象。
  • 静态只读字段在运行时初始化,其初始化发生在静态构造函数中(如果存在)或者在出现此类的任何其他静态成员之前。

注意:对于引用类型,readonly修饰符仅防止修改字段本身的值,而不是防止修改字段引用的对象。换句话说,你不能更改引用字段的指向,但是可以更改该字段指向的对象的属性或方法。

readonly修饰的字段GC如何处理它

垃圾收集器(GC)对 readonly 修饰的字段无特殊处理。只读性质并不影响对象的垃圾回收。

垃圾回收主要基于一个对象是否还被引用来决定是否进行回收。如果一个对象不再被任何其他对象引用,那么它就会被 GC 标记为可回收。当 GC 运行时,这些标记为可回收的对象将被清理掉,释放其占用的内存资源。

而对于 readonly 字段,它仅仅是限制了该字段的修改,也就是说一旦字段被初始化后,字段本身的值是不可以被改变的。然而这并不影响其所引用的对象在内存中的生命周期,也不影响垃圾回收的机制。

如果一个 readonly 字段所引用的对象不再被其他对象引用,那么这个对象同样会被标记为可回收,并在 GC 运行时被清理。

readonly修饰的字段内存分配在哪里

在C#中,readonly关键字修饰的字段的内存分配位置取决于它是否被声明为静态(static)。

  • 如果readonly字段是实例字段(非静态),那么它的内存将会在堆上分配,作为创建对象实例时分配的一部分。每个对象实例都有自己的readonly实例字段副本。
  • 如果readonly字段是静态字段,那么它的内存将会在高频堆(High Frequency Heap)上分配,此处用于存储所有的静态数据。所有实例共享一个readonly静态字段。

无论是静态还是非静态的 readonly 字段,都只能在声明时或在相应的构造函数中初始化。对于静态 readonly 字段,这通常发生在静态构造函数或者第一次引用类之前。对于非静态 readonly 字段,它们在实例构造函数中初始化。

下面是一个代码示例:

代码语言:javascript
复制
public class MyClass
{
    public readonly int InstanceField;  // 在堆上分配内存
    public static readonly int StaticField;  // 在高频堆上分配内存

    public MyClass(int value)
    {
        InstanceField = value;
    }

    // 静态构造函数
    static MyClass()
    {
        StaticField = 10;
    }
}

readonly线程安全

readonly关键字在C#中表示一旦字段被初始化,它的值就不能再被改变。这种不可变性在某种程度上可以提高多线程环境下的线程安全性。

对于值类型(如intbooldouble等)或不可变的引用类型(如string),readonly字段是绝对线程安全的,因为他们的状态一旦初始化就无法改变。

但是,对于可变的引用类型(如列表、字典或自定义类),虽然你无法改变readonly字段本身引用的对象,但你仍然可以修改该对象的内部状态。例如,你可以向一个readonly的列表中添加项目。如果不同的线程试图同时修改这个列表,那么可能会遇到线程安全问题。

以下是一个例子,解释了以上的概念:

代码语言:javascript
复制
public class MyClass
{
    public readonly List<int> MyList = new List<int>();  // 可变引用类型

    // ...其他代码...
    
    public void AddItem(int item)
    {
        // 需要保证线程安全,因为MyList是可变的
        lock (MyList)
        {
            MyList.Add(item);
        }
    }
}

readonly只能保证字段本身不会被改变,而不能保证其引用的对象的状态不被改变。在处理可变的引用类型时,还需要采取额外的同步措施以确保线程安全。

readonly修饰的对象传递的是引用还是实例

无论字段是否被 readonly 修饰,对象的传递方式(引用或值)都取决于其类型。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JusterZhu 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • readonly修饰的字段GC如何处理它
  • readonly修饰的字段内存分配在哪里
  • readonly线程安全
  • readonly修饰的对象传递的是引用还是实例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档