連載Index(読む順・公開済リンクが最新): S00_門前の誓い_総合Index
var で止まりやすいのは、使うか使わないかではなく、右辺だけで型が読めるかどうかです。var users = new List<User>() はその場で読めますが、var userId = GetUserId() は戻り値を開くまで型が見えません。
先に結論だけ書くと、new と Parse は var、戻り値だけなら型を書く、out var と匿名型は var、数値はサフィックスか型で補う、LINQ は var の前に分ける、で大半は片付きます。
以下に、迷いやすい所だけを判断表と短いコードでまとめます。後半には、レビューでそのまま返しやすい文も置いてあります。
判断表
| 場面 | 例 | 基本判断 |
|---|---|---|
| 右辺に型名が出ている |
new List<int>() Guid.Parse(text) (UserId)x
|
var でよい |
| 右辺がメソッド戻り値だけ |
GetUserId() FindOrder()
|
型を書く形を先に見る |
| 型名そのものに意味がある |
UserId Money OrderNumber
|
型を書く |
out var |
int.TryParse(text, out var count) |
var でよい |
| 数値リテラルにサフィックスがある |
0m 1.0d 1.0f
|
var でよい |
| 数値リテラルにサフィックスがない |
0 1 1.0
|
型かサフィックスを残す |
| LINQ が長い | users.Where(...).Select(...).GroupBy(...) |
var の前に分ける |
| 匿名型 | new { user.Id, user.Name } |
var 一択 |
迷った時はこの4点だけ見る
- 右辺だけで型が読めるか
- 型名が値の意味まで持っているか
- 数値や単位がその場で読めるか
- 一行に処理を入れすぎていないか
この4点で切ると、好みの話になりにくくなります。
new / 戻り値 / 数値 / LINQ で分けて決める
| 場面 | そのまま書ける例 | 見直したい例 | 理由 |
|---|---|---|---|
new |
var users = new List<User>(); |
List<User> users = new List<User>(); |
左右で同じ型名を繰り返さなくてよい |
| Parse / Cast | var userId = UserId.Parse(text); |
var value = Convert(text); |
右辺に型名があるかどうかで差が出る |
| 戻り値 | UserId userId = GetUserId(); |
var userId = GetUserId(); |
右辺だけでは型が見えない |
| 値の意味が型に乗る | Money totalPrice = GetTotalPrice(); |
var totalPrice = GetTotalPrice(); |
型名が値の種類まで伝える |
out var |
if (int.TryParse(text, out var count)) |
なし | その場で int と分かる |
| 数値 | var price = 0m; |
var price = 0; |
金額なのか件数なのかがずれやすい |
| LINQ | var activeUsers = users.Where(x => x.IsActive).ToList(); |
var x = users.Where(...).Select(...).GroupBy(...).ToDictionary(...); |
絞り込み・変換・集約が一行に寄りすぎる |
| 匿名型 | var item = new { user.Id, user.Name }; |
なし | 型名を書けない |
止まりやすい書き方と止まりにくい書き方
new と Parse は var でよい
var users = new List<User>();
var userId = UserId.Parse(text);
var price = 0m;
右辺を見た時点で型が読めます。左辺の型名を省いても、別の場所を開かずに済みます。
戻り値だけなら型を書く形を先に見る
UserId userId = GetUserId();
Money totalPrice = GetTotalPrice();
OrderNumber orderNumber = FindOrderNumber();
GetUserId() だけでは、戻り値が UserId なのか文字列なのか数値なのかが見えません。UserId や Money を左辺に出すと、型と値の意味を同時に読めます。
var userId = GetUserId();
var totalPrice = GetTotalPrice();
var orderNumber = FindOrderNumber();
この形でも変数名で補える場面はあります。とはいえ、型名まで意味を持つ値では、左辺の型を残した方が止まりにくくなります。
out var と匿名型は var でよい
if (int.TryParse(text, out var count))
{
Console.WriteLine(count);
}
var item = new { user.Id, user.Name };
out var はその行で型が見えます。匿名型は型名を書けません。
数値はサフィックスか型を残す
var count = 0;
var rate = 1.0;
var price = 0m;
count は int、rate は double、price は decimal です。
件数なら int でも問題になりにくいですが、金額や率は型の違いが計算結果へ出やすくなります。
decimal price = 0;
double rate = 1.0;
TimeSpan timeout = TimeSpan.FromSeconds(30);
数値だけでは意味が弱い所は、左辺の型で補う方が見やすくなります。
LINQ は var の前に分ける
var activeUsers = users.Where(x => x.IsActive);
var activeUserIds = activeUsers.Select(x => x.Id).ToList();
var x = users
.Where(x => x.IsActive)
.Select(x => x.Id)
.Distinct()
.OrderBy(x => x)
.ToList();
下の形が常に悪いわけではありません。
ただ、条件追加や不具合調査が入ると、絞り込み・変換・並び替え・終端処理を一行の中で追うことになります。var の前に、行を分けられないかを先に見た方が変えやすくなります。
new() は左辺が必要
List<User> users = new();
var users = new List<User>();
次は書けません。
var users = new();
new() は左辺の型が前提です。var と組み合わせる形には向きません。
レビューでそのまま返せる文
| 観点 | 確認する所 | そのまま返せる文 |
|---|---|---|
| 右辺だけで型が読めるか |
new、Parse、Cast か / 戻り値だけか |
右辺だけでは型が見えないため、ここは型を残した方が追いやすいです |
| 型名が値の意味まで持つか |
UserId Money OrderNumber など |
この型名は値の種類まで伝えるため、var より型を書いた方が意図が早く入ります |
| 数値の意味がその場で読めるか |
0 1 1.0 0m
|
ここは件数ではなく金額に見えるため、型かサフィックスを残した方が分かりやすいです |
| 一行に処理を入れすぎていないか | LINQ、メソッドチェーン |
var の前に処理を分けた方が確認しやすいです |
| 変数名だけで用途が読めるか |
data tmp ret になっていないか |
変数名だけでは用途が弱いため、命名か型のどちらかを残したいです |
早見表
| 書き方 | 判断 |
|---|---|
var x = new Foo(); |
var でよい |
var x = Foo.Parse(text); |
var でよい |
var x = GetFoo(); |
型を書く形を先に見る |
UserId x = GetUserId(); |
型を書く |
var x = 0m; |
var でよい |
var x = 0; |
用途に応じて見直す |
if (int.TryParse(text, out var x)) |
var でよい |
var x = new { user.Id, user.Name }; |
var 一択 |
var x = new(); |
書けない |
関連記事
-
var以外も含めて規約全体を見たい場合: - コーディング規約の基準(C#)|命名/例外/ログ/依存関係【掟R01】
参考リンク
- 公式リファレンス: C# の var キーワード
連載Index(読む順・公開済リンクが最新): S00_門前の誓い_総合Index