readonly (C# 參考)

readonly 關鍵字是可以在五種內容中使用的修飾詞:

  • 欄位宣告中,readonly 表示只有在宣告中或相同類別的建構函式中,才能對欄位進行指派。 可以在欄位宣告及建構函式中指派及多次重新指派 readonly 欄位。

    當建構函式結束之後,便無法指派 readonly 欄位。 此規則對實值型別及參考型別分別具有不同的含意:

    • 由於實值型別會直接包含其資料,因此具有 readonly 實值型別的欄位是不可變的。
    • 由於參考型別包含針對其資料的參考,因此 readonly 參考型別的欄位必須一律參考相同的物件。 該物件可能不可變。 readonly 修飾元可防止以參考型別的不同執行個體取代欄位值。 不過,修飾詞並無法防止欄位的執行個體資料經由唯讀欄位被修改。

    警告

    包含可變動參考型別外部可見唯讀欄位的外部可見類型是個潛在的安全性弱點,並可能會觸發警告 CA2104:「不要宣告唯讀的可變動參考類型。」

  • readonly struct 類型定義中,readonly 表示結構類型是不可變的。 如需詳細資訊,請參閱結構類型一文中的readonly結構一節。

  • 在結構類型中的執行個體成員宣告中,readonly 表示執行個體成員不會修改結構的狀態。 如需詳細資訊,請參閱結構類型一文中的readonly執行個體成員一節。

  • ref readonly 方法傳回中,readonly 修飾詞表示方法會傳回參考且不允許寫入到該參考。

唯讀欄位範例

在此範例中,無法變更 ChangeYear方法中的 year 欄位值,即使它在類別建構函式中獲指派值也是一樣:

class Age
{
    private readonly int _year;
    Age(int year)
    {
        _year = year;
    }
    void ChangeYear()
    {
        //_year = 1967; // Compile error if uncommented.
    }
}

您只能在下列內容中將值指派給 readonly 欄位︰

  • 在宣告中初始化變數時,例如︰

    public readonly int y = 5;
    
  • 在包含執行個體欄位宣告的類別執行個體建構函式。

  • 在包含靜態欄位宣告的類別靜態建構函式。

這些建構函式內容也是唯一可將 readonly 欄位作為 outref 參數有效傳遞的內容。

注意

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

您收到編譯器錯誤訊息:

無法指定唯讀欄位 (除非在建構函式或變數初始設定式中)

唯讀執行個體成員

您也可以使用 readonly 修飾詞,宣告執行個體成員不會修改結構的狀態。

public readonly double Sum()
{
    return X + Y;
}

注意

在讀取/寫入屬性的情況下,您可以將 readonly 修飾元新增至 get 存取子。 某些 get 存取子可能會執行計算並快取結果,而不只是傳回私用字段的值。 將 readonly 修飾元新增至 get 存取子,可確保 get 存取子不會藉由快取任何結果來修改對象的內部狀態。

您可以在結構類型一文的readonly執行個體成員一節中找到更多範例。

參考唯讀傳回範例

ref return 上的 readonly 修飾詞指出傳回的參考不能修改。 下列範例會傳回對來源的參考。 其會使用 readonly 修飾詞來表示呼叫端無法修改來源:

private static readonly SamplePoint s_origin = new SamplePoint(0, 0, 0);
public static ref readonly SamplePoint Origin => ref s_origin;

傳回的型別不一定得是 readonly struct。 可由 ref 傳回的任何類型,都可以由 ref readonly 傳回。

Readonly ref readonly 傳回範例

ref readonly return 也可以與 struct 類型的 readonly 執行個體成員搭配使用:

public struct ReadonlyRefReadonlyExample
{
    private int _data;

    public readonly ref readonly int ReadonlyRefReadonly(ref int reference)
    {
        // _data = 1; // Compile error if uncommented.
        return ref reference;
    }
}

方法基本上會與執行個體成員一起傳回 readonly 參考 (在此案例中為方法) readonly (無法修改任何執行個體欄位)。

C# 語言規格

如需詳細資訊,請參閱<C# 語言規格>。 語言規格是 C# 語法及用法的限定來源。

您也可以查看語言規格建議:

另請參閱