C# 13の新機能を理解する――暗黙的なインデックスアクセスとallows ref struct
【C#で知っておくべき新機能】最新バージョンを徹底解説! 第7回
ダウンロード サンプルファイル (5.5 KB)
暗黙的なインデックスアクセス(Implicit index access)
C# 13では、暗黙的に最終要素からの位置を指定するインデックス演算子(^)がオブジェクト初期化式中で利用できるようになりました。
C#では、配列の要素にアクセスする際に、最終要素からの相対位置で指定できる仕組みがあります。添え字(インデックス)にインデックス演算子(^)を付加して指定すると、先頭要素からではなく最終要素からの位置の指定になります。位置の指定は最終要素から「何番目」となるので、以下のリストのように最終要素は「^1」となります。
int[] iArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
Console.WriteLine("{0}", iArray[^1]); // 9
C# 10から使えるようになったオブジェクト初期化子においては、プロパティが配列であるとき、以下のリストのようにインデックス演算子で初期値の設定が可能です。
class Dice
{
public int[] roll { get; set; } = new int[6];
}
var dice1 = new Dice()
{
roll =
{
[0] = 1,
[1] = 2,
[2] = 3,
[3] = 4,
[4] = 5,
[5] = 6,
}
};
Console.WriteLine("{0}", dice1.roll[4]); // 5
しかしながら、インデックス演算子(^)を使おうとすると、オブジェクト初期化子中以外では問題がないのに、C# 13以前ではコンパイルエラーとなっていました。これがC# 13では以下のリストのように問題なく使えるようになりました。
+++スクリプト+++
var dice2 = new Dice()
{
roll =
{
[^1] = 1,
[^2] = 2,
[^3] = 3,
[^4] = 4,
[^5] = 5,
[^6] = 6,
}
};
Console.WriteLine("{0}", dice2.roll[4]); // 2
イテレータと非同期メソッドで使えるようになったrefとunsafe(ref and unsafe in iterators and async methods)
C# 13では、refとunsafeがイテレータと非同期メソッドで利用できるようになりました。
従来は、イテレータメソッド(yield returnを含むメソッド)と非同期メソッドの中にref変数、ref構造体、unsafeブロックを含めることはできませんでした。C# 13では、これらのもたらす効率的なメモリ管理がイテレータや非同期メソッド内で利用できるようになり、大量のデータ処理が必要な場合や、レイテンシーを抑えたい用途での効率向上が期待できます。
以下のリストは、2値を返すだけシンプルなものですが、イテレータメソッド内でref変数とref構造体を使う例です。
foreach(int d in Enumerate())
{
Console.WriteLine("{0}", d); // 123、1
}
IEnumerable<int> Enumerate()
{
int a = 123;
ref int r = ref a; // ref変数
yield return r;
Span<int> data = [1]; // ref構造体
yield return data[0];
}
続けて以下のリストは、非同期メソッド内でunsafeブロックを使う例です。ref変数とref構造体のコードは上記とほとんど同じなので省略します。配布サンプルを参照してください。
await GetAsync(); // 123、3、456
async Task GetAsync()
{
…ref変数とref構造体の例は省略…
int i = 123;
unsafe // unsafeブロック
{
int *p = &i;
*p = 456;
}
Console.WriteLine("{0}", i);
await Task.Yield();
}
最後の以下のリストは、非同期なイテレータメソッドの例です。
await foreach(int d in AsyncEnumerate())
{
Console.WriteLine("{0}", d); // 456、2、456
}
async IAsyncEnumerable<int> AsyncEnumerate()
{
int x = 123;
ref int r = ref x; // ref変数
r = 456;
await Task.Yield();
yield return x;
Span<int> d = [1, 2, 3]; // ref構造体
int v = d[1];
await Task.Yield();
yield return v;
int i = 123;
unsafe // unsafeブロック
{
int *p = &i;
*p = 456;
}
await Task.Yield();
yield return i;
}
最後のリストで、ref構造体の1要素を別変数に入れて返していますが、これはref構造体の要素をそのまま返せないためです。このように、ref変数とref構造体は、awaitやyieldをまたいで使用できない制約があります。
[NOTE]unsafeブロック
C#では、いわゆるポインタ型を使ったコードは安全でないとして既定で無効となっています。しかしながら、より実行効率を優先したコードや、メモリのきめ細かな操作のためにポインタ型や固定サイズのバッファーを有効にできるunsafeブロックが用意されています。コンパイラに/unsafeオプションを指定するか、プロジェクト設定ファイル(.csproj)の<PropertyGroup>に<AllowUnsafeBlocks>true</AllowUnsafeBlocks>を追加することで、unsafeブロックが利用できるようなります。
この記事は参考になりましたか?
- 【C#で知っておくべき新機能】最新バージョンを徹底解説!連載記事一覧
-
- C# 14の新機能を理解する──fieldキーワードとユーザー定義複合代入演算子
- C# 14の新機能を理解する――extensionブロックとnull条件付き代入
- C# 13の新機能を理解する――暗黙的なインデックスアクセスとallows ref str...
- この記事の著者
-
WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)
<WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書、記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
-
山田 祥寛(ヤマダ ヨシヒロ)
静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア
