C#では変数宣言時、型を書く必要がある。
string text = "あいうえお";
この時、var
キーワードを使用することで右辺から型を推論させて変数宣言を行える。
var text = "あいうえお";
// textはstring型となる
Visual Studioで確認すると、string
型となっていることがわかる。
var
は右辺から型を判別している。そのため、下記のコードはコンパイルエラーとなる。
var text = null;
// nullの型を判別できないためコンパイルエラーとなる
もしstring
型のnull
をvar
を使って宣言する場合、下記のように書かなければならない。
var text = (string)null;
この記法だと一応宣言はできるが、あまり型推論のメリットがない。(後述するようにメリットがない訳ではない)
var
を使うと次のメリットがある。
順番に解説する。
たとえばDictionary<Dictionary<Dictionary<int, string>, string>, Dictionary<Dictionary<int, string>, Dictionary<int, string>>>
を返すNegativeMethod
という関数があるとしよう。
これもvar
を使うと型名を書かなくてよい。
public static Dictionary<Dictionary<Dictionary<int, string>, string>, Dictionary<Dictionary<int, string>, Dictionary<int, string>>> NegativeMethod()
{
Dictionary<Dictionary<Dictionary<int, string>, string>, Dictionary<Dictionary<int, string>, Dictionary<int, string>>> something = new Dictionary<Dictionary<Dictionary<int, string>, string>, Dictionary<Dictionary<int, string>, Dictionary<int, string>>>();
// ~複雑な処理
return something;
}
Dictionary<Dictionary<Dictionary<int, string>, string>, Dictionary<Dictionary<int, string>, Dictionary<int, string>>> result = NegativeMethod();
上記のようなコードが、下記のように書ける。
public static Dictionary<Dictionary<Dictionary<int, string>, string>, Dictionary<Dictionary<int, string>, Dictionary<int, string>>> NegativeMethod()
{
var something = new Dictionary<Dictionary<Dictionary<int, string>, string>, Dictionary<Dictionary<int, string>, Dictionary<int, string>>>();
// ~複雑な処理
return something;
}
var result = NegativeMethod();
型が明確になっている場合は、複雑な型を書かなくて良くなる。Tuple
やDictionary
は複雑になる場合もあるが、それをいちいち書かなくても良いメリットとなる。なお、後述するがこういう使い方にはデメリットもあるので注意。
たとえばuserId
はint
型だったが、アルファベットを含めるという仕様変更にあたりstring
型に変更することになったとする。
ここで、下記のように修正する必要がある。
// GenerateUserIdはintを返す
int userId = GenerateUserId();
// ▲これを下記のように変更する▼
// GenerateUserIdはstringを返すようになった
string userId = GenerateUserId();
数か所であれば問題ないがもし何十箇所・何百箇所も記載してあればそれらを漏れなく修正する必要がある。
一括で置換するという方法もない訳ではないが、対象が漏れなく置換されたか、本来修正範囲外のコードが変更されていないかなどの差分確認の作業が結局発生する。
初めからvar
で記載しておけば型が変更されてもコードの修正が必要なく、修正後にテストを走らせればそれだけで済む。
// GenerateUserIdがintからstringになっても、ここは修正する必要がない
var userId = GenerateUserId();
ここは感覚的な問題だが例を示す。
下記のようなコードがあるとする。
int userId = GenerateUserId();
string firstName = "";
string lastName = "";
DateTime birthday = new DateTime(1990, 1, 1);
これはvar
を使用すると次のように書ける。
var userId = GenerateUserId();
var firstName = "";
var lastName = "";
var birthday = new DateTime(1990, 1, 1);
こうすると型の部分が全てvar
になり、変数名のインデントが揃って読みやすくなる…気がする。少なくとも私は、バラバラに型を書いているよりvar
で揃っていた方が読みやすい。
上記のようにとてもメリットの大きなvar
だが、デメリットとなるケースも存在する。
それは、人間が容易に型を推論できない場合だ。
var firstName = GetFirstName(userId);
上記の場合、おそらくfirstName
はstring
型になるだろうという想像が出来る。var
を使用するのが相応しいケースの一つだ。
しかし下記の場合はどうだろう?
var idAndNames = GetIdAndNames();
GetIdAndNames
はおそらくid
とname
を(おそらくペアで)取得するメソッドだと予想はできるが、どういう型になっているかは実装部分を見ないと判定できない。Dictionary<int, string>
かもしれないしList<Tuple<int, string>>
かもしれない。独自クラスのコレクションになっている可能性もある。
var
を使用したらGetIdAndNames
がどのような型を返すとしても寛容に受け入れてしまう反面、型が分かりにくくなるというデメリットもある。(上記の例は関数名などのネーミングの問題もあるが)
Visual StudioなどのIDE上で読むのであれば、変数名にマウスオーバーしたら型が分かるが、バージョン管理ソフトの履歴などの画面では当然そのような機能がないため読みづらい。型が分かりにくい場合は型を明記するが、コメントを添えておくと良いだろう。
コメントは後で型が変わった時などにメンテしなければならないので、明記する方が個人的には良いと思う。型を明記していればコンパイルエラーなどで検知できるので修正漏れを防ぐ助けにもなる。
// varを使わず型を明記する場合
Dictionary<int, string> = GetIdAndNames();
// コメントを添える場合
// GetIdAndNamesはDictionary<int, string>
var idAndNames = GetIdAndNames();
var
は使うべきかこれはもちろんチームのコーディング規約や方針に従わなければならないが、少なくとも私は個人開発では積極的に利用する。私がアサインされたチームでも今のところ「var
は禁止」というところはなかったので非常に助かっている。
MicrosoftのC# のコーディング規則 (C# プログラミング ガイド)にも、
変数の型が割り当ての右側から明らかである場合、または厳密な型が重要でない場合は、ローカル変数の暗黙の型指定を使用します。
と明記されている。
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント