在C#中,readonly
特性用于聲明一個只讀字段。一個只讀字段可以在聲明時或在構(gòu)造函數(shù)內(nèi)部進行初始化,一旦被賦予了初始值,它就不能被改變。
使用
下面是使用 readonly
特性的基本語法:
public readonly int MyField;
您也可以在構(gòu)造函數(shù)中初始化只讀字段,如下所示:
public class MyClass
{
public readonly int MyField;
public MyClass(int value)
{
MyField = value;
}
}
注意事項
- 只讀字段只能在聲明或者構(gòu)造函數(shù)中賦值。
- 只讀字段的值不能更改,相當于常量,但常量在編譯時需要初始化,只讀字段則在運行時初始化。
- 只讀字段可以具有不同的值,取決于所用的構(gòu)造函數(shù)來創(chuàng)建對象。
- 靜態(tài)只讀字段在運行時初始化,其初始化發(fā)生在靜態(tài)構(gòu)造函數(shù)中(如果存在)或者在出現(xiàn)此類的任何其他靜態(tài)成員之前。
注意:對于引用類型,readonly
修飾符僅防止修改字段本身的值,而不是防止修改字段引用的對象。換句話說,你不能更改引用字段的指向,但是可以更改該字段指向的對象的屬性或方法。
readonly修飾的字段GC如何處理它
垃圾收集器(GC)對 readonly
修飾的字段無特殊處理。只讀性質(zhì)并不影響對象的垃圾回收。
垃圾回收主要基于一個對象是否還被引用來決定是否進行回收。如果一個對象不再被任何其他對象引用,那么它就會被 GC 標記為可回收。當 GC 運行時,這些標記為可回收的對象將被清理掉,釋放其占用的內(nèi)存資源。
而對于 readonly
字段,它僅僅是限制了該字段的修改,也就是說一旦字段被初始化后,字段本身的值是不可以被改變的。然而這并不影響其所引用的對象在內(nèi)存中的生命周期,也不影響垃圾回收的機制。
如果一個 readonly
字段所引用的對象不再被其他對象引用,那么這個對象同樣會被標記為可回收,并在 GC 運行時被清理。
readonly修飾的字段內(nèi)存分配在哪里
在C#中,readonly
關(guān)鍵字修飾的字段的內(nèi)存分配位置取決于它是否被聲明為靜態(tài)(static
)。
- 如果
readonly
字段是實例字段(非靜態(tài)),那么它的內(nèi)存將會在堆上分配,作為創(chuàng)建對象實例時分配的一部分。每個對象實例都有自己的readonly
實例字段副本。 - 如果
readonly
字段是靜態(tài)字段,那么它的內(nèi)存將會在高頻堆(High Frequency Heap)上分配,此處用于存儲所有的靜態(tài)數(shù)據(jù)。所有實例共享一個readonly
靜態(tài)字段。
無論是靜態(tài)還是非靜態(tài)的 readonly
字段,都只能在聲明時或在相應(yīng)的構(gòu)造函數(shù)中初始化。對于靜態(tài) readonly
字段,這通常發(fā)生在靜態(tài)構(gòu)造函數(shù)或者第一次引用類之前。對于非靜態(tài) readonly
字段,它們在實例構(gòu)造函數(shù)中初始化。
下面是一個代碼示例:
public class MyClass
{
public readonly int InstanceField; // 在堆上分配內(nèi)存
public static readonly int StaticField; // 在高頻堆上分配內(nèi)存
public MyClass(int value)
{
InstanceField = value;
}
// 靜態(tài)構(gòu)造函數(shù)
static MyClass()
{
StaticField = 10;
}
}
readonly線程安全
readonly
關(guān)鍵字在C#中表示一旦字段被初始化,它的值就不能再被改變。這種不可變性在某種程度上可以提高多線程環(huán)境下的線程安全性。
對于值類型(如int
、bool
、double
等)或不可變的引用類型(如string
),readonly
字段是絕對線程安全的,因為他們的狀態(tài)一旦初始化就無法改變。
但是,對于可變的引用類型(如列表、字典或自定義類),雖然你無法改變readonly
字段本身引用的對象,但你仍然可以修改該對象的內(nèi)部狀態(tài)。例如,你可以向一個readonly
的列表中添加項目。如果不同的線程試圖同時修改這個列表,那么可能會遇到線程安全問題。
以下是一個例子,解釋了以上的概念:
public class MyClass
{
public readonly List<int> MyList = new List<int>(); // 可變引用類型
// ...其他代碼...
public void AddItem(int item)
{
// 需要保證線程安全,因為MyList是可變的
lock (MyList)
{
MyList.Add(item);
}
}
}
readonly
只能保證字段本身不會被改變,而不能保證其引用的對象的狀態(tài)不被改變。在處理可變的引用類型時,還需要采取額外的同步措施以確保線程安全。
readonly修飾的對象傳遞的是引用還是實例
無論字段是否被 readonly
修飾,對象的傳遞方式(引用或值)都取決于其類型。
該文章在 2023/10/30 11:16:25 編輯過