SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

【C#で知っておくべき新機能】最新バージョンを徹底解説!

C# 13の新機能を理解する――paramsコレクションと新しいロックセマンティクス

【C#で知っておくべき新機能】最新バージョンを徹底解説! 第6回

  • X ポスト
  • このエントリーをはてなブックマークに追加

paramsコレクション(Params collections)

 C# 13では、params(可変長引数)に、コレクション式で使える型を利用できるようになりました。

 C#のメソッドには、可変長引数を受け取る仕組みがあります。これは、paramsと呼ばれます。配列を受け取るメソッドにおいてparamsを使うと、個別の変数をそのままメソッドの引数として渡すことができます。

リスト:params/Program.cs
double a = 3.14159, b = 1.41421, c = 2.2362, d = 2.71828, e = 1.61803;
ave = CalcAverageParams(a, b, c, d, e);		// 直接渡せる
Console.WriteLine($"With params: {ave}");	// With params: 2.225662

double CalcAverageParams(params double[] a)	// paramsを指定して配列で受ける
{
    double sum = 0;
    for (int i = 0; i < a.Length; i++)
    {
        sum += a[i];
    }
    return sum / a.Length;
}

 従来は、paramsで渡せるのは基本的に配列のみでしたが、C# 13では配列を含むコレクション式を渡せるようになりました。コレクション式とは、C# 12で導入された、配列やコレクションを大カッコ([ ])で初期化できる記法です。このコレクション式については第4回で紹介しました。

 C# 13では、上記のリストは以下のように書き換えられます。

リスト:params/Program.cs
double ave;
double a = 3.14159, b = 1.41421, c = 2.2362, d = 2.71828, e = 1.61803;
ave = CalcAverageList(a, b, c, d, e);
Console.WriteLine($"With List: {ave}");		// With List: 2.225662
double CalcAverageList(params List<double> a)
    …関数の中身はCountプロパティに書き換えただけなので省略…

ave = CalcAverageIEnumerable(a, b, c, d, e);
Console.WriteLine($"With IEnumerable: {ave}");	// With IEnumerable: 2.225662
double CalcAverageIEnumerable(params IEnumerable<double> a)
    …関数の中身はforeach文に書き換えただけなので省略…

ave = CalcAverageReadOnlySpan(a, b, c, d, e);
Console.WriteLine($"With ReadOnlySpan: {ave}");	// With ReadOnlySpan: 2.225662
double CalcAverageReadOnlySpan(params ReadOnlySpan<double> a)
    …関数の中身は配列版に同じなので省略…

ave = CalcAverageSpan(a, b, c, d, e);
Console.WriteLine($"With Span: {ave}");		// With Span: 2.225662
double CalcAverageSpan(params Span<double> a)
    …関数の中身は配列版に同じなので省略…

新しいロックセマンティクス(New lock object)

 C# 13では、lock文でLockオブジェクトを特別扱いするようになりました。

 lock文は、マルチスレッド環境において排他制御を行うための構文です。以下のように、排他制御に使うオブジェクト(同期オブジェクト)を、排他制御の必要な期間(クリティカルセクション)の開始時に自動でロックして(排他ロック)、終了時に自動で解放(アンロック)する処理を記述できます。

 同期オブジェクトがロックされている間、他のスレッドは同期オブジェクトをロックしたくてもできないので、クリティカルセクション内で排他的な処理を記述できます。

同期オブジェクト生成
lock(同期オブジェクト)		// 排他ロック(二重ロック不可)
{
    クリティカルセクション	// ここを実行できるのは常に単一のスレッドのみ
}				// アンロック

 従来のC#では、同期オブジェクトには任意のオブジェクト(objectオブジェクトなど)などを使うことで、lock文において排他制御のためのSystem.Threading.Monitorクラスを使うコードに展開されていました。Monitorクラスによる排他制御は速度面で不利な面があるため、.NET 9で新しい排他制御のためのクラスLockが追加されました。これに伴い、同期オブジェクトにはLockオブジェクトを使います。lock文の書き方自体は変わりませんが、C# 13ではSystem.Threading.Lockクラスを使うコードに展開されます。

 以下は、2つのロック方法にかかる時間を比較する例です。複数のスレッドを起動し、ダミーの計算処理を実行しています。スレッドの起動と終了の時間をStopwatchクラスで計測して合計値とともに表示します。

リスト:lock/Program.cs
using System.Diagnostics;

const int NumberOfThread = 10;		// スレッドの個数
const int NumberOfLoop = 100000;	// スレッド内で実行するループの回数
long sum;				// ダミーの計算処理用
var sw = new Stopwatch();		// 実行時間計測用

// 従来のlock
var syncObject = new object();		// 任意のオブジェクト
sum = 0;				// 計算値をリセット
sw.Reset();				// 計測開始
sw.Start();
Parallel.For(0, NumberOfThread, i =>	// スレッド起動
{
    for (int j = 0; j < NumberOfLoop; j++)	// 繰り返し開始
    {
        lock (syncObject)		// 同期オブジェクトのロック
        {
            int tmp = sum + i;		// ダミーの計算処理
            sum = tmp + j;
        }
    }
});
sw.Stop();				// 計測終了
Console.Write("sync object: {0}: {1}\n", sum, sw.Elapsed);	// 結果表示

// 新しいlock
var lockObject = new Lock();		// Lockオブジェクトとする
sum = 0;				// 計算値をリセット
sw.Reset();
sw.Start();
Parallel.For(0, NumberOfThread, i =>
{
    for (int j = 0; j < NumberOfLoop; j++)
    {
        lock (lockObject)	// 同期オブジェクト(Lockオブジェクト)のロック
        {
            int tmp = sum + i;	// ダミーの計算処理
            sum = tmp + j;
        }
    }
});
sw.Stop();
Console.Write("lock object: {0}: {1}\n", sum, sw.Elapsed);

 実行すると、Lockオブジェクトを用いた繰り返しの方が高速であることが分かります。

sync object: 500400000: 00:00:00.0213048
lock object: 500400000: 00:00:00.0045708

次のページ
新しいエスケープシーケンス\e(New escape sequence)

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
【C#で知っておくべき新機能】最新バージョンを徹底解説!連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 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本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/20750 2025/01/17 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング