分享方式:


ref 結構類型 (C# 參考)

您可以在結構類型的宣告中,使用 ref 修飾詞。 ref struct 類型的執行個體,會配置在堆疊上,且無法逸出至受控堆積。 為確保這一點,編譯器對於 ref struct 類型的使用限制如下:

  • ref struct 不能是陣列的元素類型。
  • ref struct 不能是類別或非 ref struct 欄位的宣告類型。
  • 無法將 ref struct box 到 System.ValueTypeSystem.Object
  • Lambda 運算式區域函式無法擷取 ref struct 變數。
  • 在 C# 13 之前, ref struct 無法在 方法中使用 async 變數。 從 C# 13 開始,ref struct 變數不能用於 async 方法中 await 表達式的相同區塊中。 但是您可以在同步方法中使用 ref struct 變數,例如,用在傳回 TaskTask<TResult> 的方法中。
  • 在 C# 13 之前,ref struct 變數不能用於迭代器中。 從 C# 13 開始,可以在迭代器中使用 ref struct 類型和 ref 區域變數,前提是其不在 yield return 陳述式的程式碼區段中。
  • 在 C# 13 之前,ref struct 無法實作介面。 從 C# 13 開始,ref 結構可以實作介面,但必須遵守 ref 安全規則。 例如,ref struct 型別無法轉換成介面型別,因為需要 Boxing 轉換。
  • 在 C# 13 之前,ref struct 不能是型別引數。 從 C# 13 開始,當型別參數在其 where 子句中指定 allows ref struct 時,ref struct 可以是型別引數。

一般而言,當您需要也包含 ref struct 類型的資料成員之類型時,要定義 ref struct 類型:

public ref struct CustomRef
{
    public bool IsValid;
    public Span<int> Inputs;
    public Span<int> Outputs;
}

若要將 ref struct 宣告為 readonly,請在型別宣告中合併 readonlyref 修飾詞 (readonly 修飾詞必須位於 ref 修飾詞之前):

public readonly ref struct ConversionRequest
{
    public ConversionRequest(double rate, ReadOnlySpan<double> values)
    {
        Rate = rate;
        Values = values;
    }

    public double Rate { get; }
    public ReadOnlySpan<double> Values { get; }
}

在 NET 中,ref struct 的範例為 System.Span<T>System.ReadOnlySpan<T>

ref 欄位

從 C# 11 開始,您可以在 ref struct 中宣告 ref 欄位,如下列範例所示:

public ref struct RefFieldExample
{
    private ref int number;

    public int GetNumber()
    {
        if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
        {
            throw new InvalidOperationException("The number ref field is not initialized.");
        }

        return number;
    }
}

ref 欄位的值可能為 null。 使用 Unsafe.IsNullRef<T>(T) 方法可判斷 ref 欄位是否為 null

您可用下列方式,對 ref 欄位套用 readonly 修飾詞:

  • readonly ref:只有在建構函式或 init 存取子內,可以用 = ref 運算子,ref 重新指定這樣的欄位。 您可以利用欄位存取修飾詞,在允許的任何時間點,使用 = 運算子來指派值。
  • ref readonly:您任何時間點都無法對此類欄位指派包含 = 運算子的值。 但可以使用 = ref 運算子,ref 重新指派欄位。
  • readonly ref readonly:您只能在建構函式或 init 存取子中,重新指派。這樣的欄位。 您任何時間點都無法對欄位指派值。

編譯器可確保儲存在 ref 欄位中的參考不會比其所參考的值存留更久。

ref 欄位功能可讓您安全實作類型,例如 System.Span<T>

public readonly ref struct Span<T>
{
    internal readonly ref T _reference;
    private readonly int _length;

    // Omitted for brevity...
}

Span<T> 類型會儲存參考,以透過參考來存取記憶體中的連續元素。 使用參考可讓 Span<T> 執行個體避免複製其參考的儲存體。

可處置模式

您可以定義可處置的 ref struct。 若要這樣做,請確定 ref struct 符合可處置模式。 也就是說,它有執行個體 Dispose 方法,可供存取、無參數,且有 void 傳回型別。 您可以使用 using 陳述式或宣告,搭配可處置 ref struct 的執行個體。

從 C# 13 開始,您也可以在 ref struct 型別上實作 IDisposable。 不過,多載解析偏好介面方法的可處置模式。 找不到適當的 Dispose 方法時,編譯器只會解析成 IDisposable.Dispose 方法。

實作介面的 ref struct 型別限制

這些限制可確保實作介面的 ref struct 型別遵守必要的 ref 安全規則。

  • ref struct 無法轉換成它所實作之介面的執行個體。 參數若為介面型別,當您使用 ref struct 型別作為引數時,此限制會包括隱含轉換。 轉換會導致 Boxing 轉換,這違反了 ref 安全。
  • 實作介面的 ref struct 必須實作所有介面成員。 ref struct 必須實作介面包括預設實作的成員。

編譯器會強制執行這些限制。 如果您撰寫實作介面的 ref struct 型別,則每個新的更新都可能包括新的預設介面成員。 在您提供這些新方法的實作之前,您的應用程式不會編譯。

重要

實作介面的 ref struct 包括後續原始檔中斷和二進位中斷變更的可能性。 如果 ref struct 實作在另一個組件中定義的介面,而且該組件提供將預設成員新增至該介面的更新,即會發生中斷。

當您重新編譯 ref struct 時,就會發生原始檔中斷:它必須實作新成員,即使有預設的實作也一樣。

如果您升級外部組件而不重新編譯 ref struct 型別,而且更新的程式碼會呼叫新方法的預設實作,即會發生二進位中斷。 存取預設成員時,執行階段會擲回例外狀況。

C# 語言規格

如需詳細資訊,請參閱 C# 語言規格的下列幾節:

如需 ref 欄位的詳細資訊,請參閱低階結構改善提案附註。

另請參閱