次の方法で共有


インライン配列宣言に関連するエラーと警告の解決

この記事では、コンパイラの次のエラーと警告について説明します。

  • CS9164: 代入できる変数ではないため、式を Span<T> に変換できません
  • CS9165: 参照で渡すこと、または返すことができないため、式を ReadOnlySpan<T> に変換できません
  • CS9166: インデックスがインライン配列の範囲外です
  • CS9167: インライン配列の長さは 0 より大きくする必要があります。
  • CS9168: インライン配列構造体では、レイアウトを明示的に指定できません。
  • CS9169: インライン配列構造体では、ref フィールドではないインスタンス フィールドを 1 つだけ宣言する必要があります。
  • CS9172: インライン配列型の要素には、intSystem.Index、または System.Range に暗黙的に変換できる 1 つの引数でのみアクセスできます。
  • CS9173: インライン配列のアクセスには、名前付き引数の指定子を使えません
  • CS9180: インライン配列の要素フィールドは、required、readonly、volatile、または固定サイズのバッファーとして宣言することはできません。
  • CS9181: インライン配列のインデクサーは、要素アクセス式には使われません。
  • CS9182: インライン配列の "Slice" メソッドは、要素アクセス式には使われません。
  • CS9183: インライン配列の変換演算子は、宣言する型の式からの変換には使われません。
  • CS9184: "インライン配列" 言語機能は、"ref" フィールドである要素フィールド、または型引数として有効ではない型を持つ要素フィールドを含むインライン配列型では、サポートされていません。
  • CS9189: インライン配列型に対する foreach ステートメントはサポートされていません

インライン配列宣言

インライン配列は、フィールド 1 つと配列の長さを指定する属性 1 つを持つ struct 型として宣言します。 コンパイラは、無効なインライン配列宣言には次のエラーを発生させます。

  • CS9167: インライン配列の長さは 0 より大きくする必要があります。
  • CS9168: インライン配列構造体では、レイアウトを明示的に指定できません。
  • CS9169: インライン配列構造体では、ref フィールドではないインスタンス フィールドを 1 つだけ宣言する必要があります。
  • CS9180: インライン配列の要素フィールドは、required、readonly、volatile、または固定サイズのバッファーとして宣言することはできません。
  • CS9184 "インライン配列" 言語機能は、"ref" フィールドである要素フィールド、または型引数として有効ではない型を持つ要素フィールドを含むインライン配列型では、サポートされていません。

こうした配列を修正するには、次の条件を満たすようにします。

  • System.Runtime.CompilerServices.InlineArrayAttribute の引数は正の整数である。
  • 外側の struct ではレイアウトを明示的に指定しない。
  • 外側の struct にはインスタンス フィールドが 1 つあり、そのインスタンス フィールドは ref フィールドではない。
  • 単一インスタンス フィールドは、固定サイズのバッファーではありません。
  • 単一インスタンス フィールドには、requiredvolatile、または readonly 修飾子は含まれません。

要素アクセス

インライン配列の要素には、通常の配列と同じ方法でアクセスします。 要素へのアクセスが正しくない場合、コンパイラで次のエラーが発生します。

  • CS9166: インデックスがインライン配列の範囲外です
  • CS9172: インライン配列型の要素には、intSystem.Index、または System.Range に暗黙的に変換できる 1 つの引数でのみアクセスできます。
  • CS9173: インライン配列のアクセスには、名前付き引数の指定子を使えません
  • CS9189: インライン配列型に対する foreach ステートメントはサポートされていません

さらに、インデクサーを宣言すると、コンパイラで次の警告が発生します。

  • CS9181: インライン配列のインデクサーは、要素アクセス式には使われません。

インライン バッファーに対して生成されたコードは、バッファーのメモリに直接アクセスし、宣言されたインデクサーをバイパスします。 インライン配列を foreach ステートメントで使うことはできません。

インデクサーの引数は以下のものである必要があります。

  • intSystem.IndexSystem.Range の 3 つの型のいずれかであること。
  • 名前付き引数は使えません。 コンパイラが要素のアクセサーを生成します。 パラメーターには名前がないため、名前付き引数を使用することはできません。
  • 配列の範囲内にあること。 すべての .NET 配列と同様に、インライン配列の要素アクセスでは範囲内であるかどうかがチェックされます。 インデックスは、インライン配列の範囲内である必要があります。

Span への変換

インライン配列を扱う場合は、System.Span<T>System.ReadOnlySpan<T> をよく使用します。 コンパイラは、無効な変換には次のエラーを発生させます。

  • CS9164: 代入できる変数ではないため、式を Span<T> に変換できません
  • CS9165: 参照で渡すこと、または返すことができないため、式を ReadOnlySpan<T> に変換できません

コンパイラによって生成されたコードは、インライン バッファーのメモリに直接アクセスします。 そのため、一部のメンバーは呼び出されません。 呼び出されないメンバーのいずれかを記述すると、コンパイラで次の警告が発生します。

  • CS9182: インライン配列の "Slice" メソッドは、要素アクセス式には使われません。
  • CS9183: インライン配列の変換演算子は、宣言する型の式からの変換には使われません。

インライン配列は、Span<T> または ReadOnlySpan<T> に暗黙的に変換して、インライン配列をメソッドに渡すことができます。 コンパイラは、そうした変換に次の制限を適用します。

  • インライン配列を Span<T> に変換するには、インライン配列は書き込み可能である必要があります。 配列が読み取り専用の場合、書き込み可能な Span<T> に変換することはできません。 代わりに、ReadOnlySpan<T> を使用できます。
  • 変換が成功するには、インライン配列の "安全なコンテキスト" の幅が、Span<T> または ReadOnlySpan<T> の "安全なコンテキスト" の幅以上である必要があります。 Span のコンテキストを制限するか、インライン配列の範囲を広げる必要があります。

さらに、コンパイラがインライン バッファー内で Slice メソッドの呼び出しを生成することはありません。 インライン バッファーを Span または ReadOnlySpan に変換する変換演算子は呼び出されません。 コンパイラは、メモリ バッファーから System.Span<T> または System.ReadOnlySpan<T> を直接作成するコードを生成します。