2つの変数の中身を入れ替える方法を4種類紹介したいと思います。
(1) 昔ながらの方法
教科書に書いてあるやつ。最も一般的な方法。大抵の言語でもこうやって入れ替えられます。
int a = 10; int b = 20; int _tmp = a; a = b; b = _tmp; // > a=20, b=10
ローカル変数がひとつ必要になります。以下のように中カッコのスコープを切って処理する小技もある。
int a = 10; int b = 20; { int _tmp = a; a = b; b = _tmp; } // こうやって中カッコでくくると _tmp 変数自体がこの「}」を抜ける時に消えるので少し安心できる
但しこんな事するくらいなら細かくメソッドに分割したほうがマシかもしれません。
(2) Tupleを使う
C#7.0で導入されたタプルという機能を使用します。見た目が非常にシンプル。余計な変数が必要ない。ただし .NET のバージョンによっては使えないことがある もはや使えない環境は殆どないので C# ではこちらのほう標準かもしれません。
- 推奨環境条件
- C#7.0
- .NET Core 2.0以降
- .NET Framework 4.7以降
- IDEの構文サポート
int a = 10; int b = 20; (a, b) = (b, a); // > a=20, b=10
ValueTuple に対する「()」(丸括弧)を使った省略記法をC#7.0以降から使用可能のためいったん Tuple にまとめて置換すると簡潔に記述できる。余計な変数が必要ない。コンパイルすると変数3つでスワップになるためやってることは古典的な方法と同じ。
これ以前のバージョンでも 追加パッケージを導入すれば ValueTuple は使える。VisualStudio 2017 + .NET4.5 では以下エラーが表示されます。
エラー CS8179 定義済みの型 'System.ValueTuple`2' は定義、またはインポートされていません
Nuget から System.ValueTuple を追加するとエラーが出なくなります。
ViusalStudio2017 より前の環境ではパッケージを追加しても IDE 自体が構文サポートをしていないので赤い波線がでエラー表示が出ます。コンパイルはできる謎の環境になる場合があります。ただし可能であれば新しいVSに乗り換えたほうがいいです。というかもしIDEが会社の金なら即座に乗り換えるべき。C#ならデメリット無いのでは?VC++はしらぬ。 さっさと2019などに移行しましょう。
(3) 外部のメソッドで入れ替える
この方法は微妙かもしれません。ただ、言語バージョン依存が存在しないためどのC#でも使えます。
// ValueUtil.cs public static class ValueUtil { public static void Swap<T>(ref T a, ref T b) { T _tmp = a; a = b; b = _tmp; } } int a = 10; int b = 20; ValueUtil.Swap(ref a, ref b); // > a=20, b=10
ref を引数に指定しないといけなのが若干気になるりますね。
(4) 拡張メソッドで入れ替える(値型のみ)方法
この方法は構造体(値型)のみ適用できます。変数のメソッドとして実行できるのである意味直観的かも?
C#7.2以降で使用可能な構文を使用する。
- 環境条件
- C# 7.2
- .NET Core2.1以降
- .NET Framework 4.7以降 (オプションが指定必要)
- ref 拡張メソッド構文のサポート
// StructExtension.cs public static class StructExtension { public static void Swap<T>(ref this T self, ref T tgt) where T : struct { T _tmp = self; self = tgt; tgt = _tmp; } } int a = 10; int b = 20; a.Swap(ref b); // > a=20, b=10
クラスは言語仕様上の問題で入れ替え不可。これもやや新しい機能のため使用に制約があります。
余談ですが、この書き方で拡張メソッドを記述すると全ての型にメソッドが追加されたように見せられるのでこの書き方が言語拡張の機能として使用できます。ただ乱用すると標準の C# と使用感が大きく変わってしまいます。
ほかにあるかな?
後ろ2つはやや無理やりでしたが、何かあれば随時。