C#——關鍵字:readonly
C#——關鍵字:readonly
readonly 關鍵字是一個可在四個上下文中使用的修飾符:
-
在欄位宣告中,readonly 指示只能在宣告期間或在同一個類的建構函式中向欄位賦值。 可以在欄位宣告和建構函式中多次分配和重新分配只讀欄位。
建構函式退出後,不能分配 readonly 欄位。 此規則對於值型別和引用型別具有不同的含義:
1.由於值型別直接包含資料,因此屬於 readonly 值型別的欄位不可變。
2.由於引用型別包含對其資料的引用,因此屬於 readonly 引用型別的欄位必須始終引用同一物件。 該物件是可變的。 readonly 修飾符可防止欄位替換為引用型別的其他例項。 但是,修飾符不會阻止通過只讀欄位修改欄位的例項資料。
警告
包含屬於可變引用型別的外部可見只讀欄位的外部可見型別可能存在安全漏洞,可能會觸發警告 CA2104:“不要宣告只讀可變引用型別。” -
在 readonly struct 型別定義中,readonly 指示結構型別是不可變的。 有關詳細資訊,請參閱結構型別一文中的 readonly 結構一節。
-
在結構型別內的例項成員宣告中,readonly 指示例項成員不修改結構的狀態。 有關詳細資訊,請參閱結構型別一文中的 readonly 例項成員部分。
-
在 ref readonly 方法返回中,readonly 修飾符指示該方法返回一個引用,且不允許向該引用寫入內容。
在 C# 7.2 中添加了 readonly struct 和 ref readonly 上下文。 在 C# 8.0 中添加了 readonly 結構成員
Readonly 欄位示例
在此示例中,即使在類建構函式中給欄位 year 賦了值,也無法在方法 ChangeYear 中更改其值:
class Age
{
readonly int year;
Age(int year)
{
this.year = year;
}
void ChangeYear()
{
//year = 1967; // Compile error if uncommented.
}
}
只能在下列上下文中對 readonly 欄位進行賦值:
- 在宣告中初始化變數時,例如:
public readonly int y = 5;
- 在包含例項欄位宣告的類的例項建構函式中。
- 在包含靜態欄位宣告的類的靜態建構函式中。
只有在這些建構函式上下文中,將 readonly 欄位作為 out 或 ref 引數傳遞才有效。
備註:
readonly 關鍵字不同於 const 關鍵字。 const 欄位只能在該欄位的宣告中初始化。 可以在欄位宣告和任何建構函式中多次分配 readonly 欄位。 因此,根據所使用的建構函式,readonly 欄位可能具有不同的值。 另外,雖然 const 欄位是編譯時常量,但 readonly 欄位可用於執行時常量,如下面的示例所示:
public static readonly uint timeStamp = (uint)DateTime.Now.Ticks;
public class SamplePoint
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;
public SamplePoint()
{
// Initialize a readonly instance field
z = 24;
}
public SamplePoint(int p1, int p2, int p3)
{
x = p1;
y = p2;
z = p3;
}
public static void Main()
{
SamplePoint p1 = new SamplePoint(11, 21, 32); // OK
Console.WriteLine($"p1: x={p1.x}, y={p1.y}, z={p1.z}");
SamplePoint p2 = new SamplePoint();
p2.x = 55; // OK
Console.WriteLine($"p2: x={p2.x}, y={p2.y}, z={p2.z}");
}
/*
Output:
p1: x=11, y=21, z=32
p2: x=55, y=25, z=24
*/
}
在前面的示例中,如果使用類似以下示例的語句:
p2.y = 66; // Error
你將收到編譯器錯誤訊息:
無法對只讀的欄位賦值(建構函式或變數初始值指定項中除外)
Ref readonly 返回示例
ref return 上的 readonly 修飾符指示返回的引用無法修改。 下面的示例返回了一個對來源的引用。 它使用 readonly 修飾符來指示呼叫方無法修改來源:
private static readonly SamplePoint origin = new SamplePoint(0, 0, 0);
public static ref readonly SamplePoint Origin => ref origin;
所返回的型別不需要為 readonly struct。 ref 能返回的任何型別都能由 ref readonly 返回。