次の方法で共有


ref 構造体型 (C# リファレンス)

構造体型を宣言するときは、ref修飾子を使用します。 ref struct型のインスタンスをスタックに割り当てます。マネージド ヒープにエスケープすることはできません。 このプロパティを確保するために、コンパイラは ref struct 型の使用を次のように制限します。

  • 配列の要素型として ref struct を使用することはできません。
  • クラスまたは非ref structのフィールドの型としてref structを宣言することはできません。
  • System.ValueTypeまたはSystem.Objectするref structにボックスを設定することはできません。
  • ラムダ式またはローカル関数ref struct変数をキャプチャすることはできません。
  • C# 13 より前では、async メソッドでref struct変数を使用することはできません。 C# 13 以降では、ref struct 変数は await メソッド内の async 式と同じブロック内で使用できません。 ただし、同期メソッドでは ref struct 変数を使用できます (Task または Task<TResult> を返すメソッドなど)。
  • C# 13 より前では、反復子ref struct変数を使用することはできません。 C# 13 以降では、ref struct 型と ref ローカルは、yield return ステートメントを含むコード セグメントの中にない場合は、反復子の中で使用できます。
  • C# 13 より前では、ref struct はインターフェイスを実装できません。 C# 13 以降、ref 構造体はインターフェイスを実装できますが、ref 安全性規則に従う必要があります。 たとえば、ref struct 型はボックス化変換が必要なため、インターフェイス型に変換できません。
  • C# 13 より前では、ref struct を型引数にすることはできません。 C# 13 以降では、型パラメーターの ref struct 句で allows ref struct を指定する場合、where を型引数として使用できます。

C# 言語リファレンスには、C# 言語の最新リリース バージョンが記載されています。 また、今後の言語リリースのパブリック プレビューの機能に関する初期ドキュメントも含まれています。

このドキュメントでは、言語の最後の 3 つのバージョンまたは現在のパブリック プレビューで最初に導入された機能を特定します。

ヒント

C# で機能が初めて導入された時期を確認するには、 C# 言語バージョン履歴に関する記事を参照してください。

通常、ref struct 型のデータ メンバーも含む型が必要な場合は、ref struct 型を定義します。

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

ref structreadonly として宣言するには、型宣言内で readonly 修飾子と ref 修飾子を組み合わせます (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 フィールド

次の例に示すように、refref struct フィールドを宣言できます。

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 メソッドを使用します。

readonly 修飾子は、次の方法で ref フィールドに適用できます。

  • readonly ref: コンストラクターまたはinitアクセサー内でのみ、= ref演算子を使用して、このフィールドを再割り当てできます。 フィールド アクセス修飾子によって許可される任意の時点で、= 演算子を使用して値を割り当てることができます。
  • ref readonly: どの時点でも、 = 演算子を持つ値をこのフィールドに割り当てることはできません。 ただし、 = 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 以降では、IDisposable 型に ref struct を実装することもできます。 ただし、オーバーロードの解決では、インターフェイス メソッドよりも破棄可能なパターンが優先されます。 コンパイラは、適切なIDisposable.Dispose メソッドが見つからない場合にのみ、Dispose メソッドに解決されます。

インターフェイスを実装する ref struct 型の制限事項

これらの制限により、インターフェイスを実装する ref struct 型が、必要な ref 安全 規則に従っていることを確認できます。

  • ref structを実装するインターフェイスのインスタンスに変換することはできません。 この制限には、引数として ref struct 型を使用し、パラメーターがインターフェイス型である場合の暗黙的な変換が含まれます。 変換によってボックス化変換が行われるので、参照の安全性に違反します。 ref struct は、明示的なインターフェイス宣言としてメソッドを宣言できます。 ただし、これらのメソッドには、型パラメーターが型を allows ref struct ジェネリック メソッドからのみアクセスできます。
  • インターフェイス を実装する ref struct は、すべてのインスタンス インターフェイス メンバー 実装する必要があります。 インターフェイスに既定の実装が含まれている場合でも、ref struct はインスタンス メンバーを実装する必要があります。

コンパイラはこれらの制限事項を適用します。 インターフェイスを実装する ref struct 型を作成すると、新しい更新プログラムごとに新しい既定のインターフェイス メンバーが含まれる可能性があります。 新しいインスタンス メソッドの実装を提供するまで、アプリケーションはコンパイルされません。 既定の実装を使用して、static インターフェイス メソッドの特定の実装を指定することはできません。

重要

ref struct型を持つインターフェイスを実装すると、後でソース破壊的変更とバイナリ破壊的変更が発生する可能性があります。 中断は、 ref struct が別のアセンブリで定義されているインターフェイスを実装し、そのアセンブリがそのインターフェイスに既定のメンバーを追加する更新プログラムを提供する場合に発生します。

ソースの中断は、 ref structを再コンパイルするときに発生します。既定の実装がある場合でも、新しいメンバーを実装する必要があります。

バイナリ区切りは、 ref struct 型を再コンパイルせずに外部アセンブリをアップグレード し、 更新されたコードが新しいメソッドの既定の実装を呼び出した場合に発生します。 既定のメンバーにアクセスすると、ランタイムは例外をスローします。

C# 言語仕様

詳細については、「C# 言語仕様」の次のセクションを参照してください。

ref フィールドの詳細については、「低レベル構造体の機能強化」の提案メモを参照してください。

関連項目