tag:crieit.net,2005:https://crieit.net/tags/%E6%9A%97%E9%BB%99%E7%9A%84%E5%9E%8B%E6%8C%87%E5%AE%9A/feed 「暗黙的型指定」の記事 - Crieit Crieitでタグ「暗黙的型指定」に投稿された最近の記事 2021-01-06T20:09:22+09:00 https://crieit.net/tags/%E6%9A%97%E9%BB%99%E7%9A%84%E5%9E%8B%E6%8C%87%E5%AE%9A/feed tag:crieit.net,2005:PublicArticle/16547 2021-01-06T20:08:06+09:00 2021-01-06T20:09:22+09:00 https://crieit.net/posts/csharp-var 【C#】varの使い方、メリットとデメリット <h1 id="使い方"><a href="#%E4%BD%BF%E3%81%84%E6%96%B9">使い方</a></h1> <p>C#では変数宣言時、型を書く必要がある。</p> <pre><code class="csharp">string text = "あいうえお"; </code></pre> <p>この時、<code>var</code>キーワードを使用することで右辺から型を推論させて変数宣言を行える。</p> <pre><code class="csharp">var text = "あいうえお"; // textはstring型となる </code></pre> <p>Visual Studioで確認すると、<code>string</code>型となっていることがわかる。<br /> <a href="https://crieit.now.sh/upload_images/e84f7ee882c4fb25f5501a6ff08accd65ff59a5ca7382.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/e84f7ee882c4fb25f5501a6ff08accd65ff59a5ca7382.jpg?mw=700" alt="image" /></a></p> <p><code>var</code>は右辺から型を判別している。そのため、下記のコードはコンパイルエラーとなる。</p> <pre><code class="csharp">var text = null; // nullの型を判別できないためコンパイルエラーとなる </code></pre> <p>もし<code>string</code>型の<code>null</code>を<code>var</code>を使って宣言する場合、下記のように書かなければならない。</p> <pre><code class="csharp">var text = (string)null; </code></pre> <p>この記法だと一応宣言はできるが、あまり型推論のメリットがない。(後述するようにメリットがない訳ではない)</p> <h1 id="メリット"><a href="#%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88">メリット</a></h1> <p><code>var</code>を使うと次のメリットがある。</p> <ul> <li>複雑な型名を書かなくても良い</li> <li>型が変更されたときに書き直さなくても良い</li> <li>コードが読みやすくなる</li> </ul> <p>順番に解説する。</p> <h2 id="複雑な型名を書かなくても良い"><a href="#%E8%A4%87%E9%9B%91%E3%81%AA%E5%9E%8B%E5%90%8D%E3%82%92%E6%9B%B8%E3%81%8B%E3%81%AA%E3%81%8F%E3%81%A6%E3%82%82%E8%89%AF%E3%81%84">複雑な型名を書かなくても良い</a></h2> <p>たとえば<code>Dictionary<Dictionary<Dictionary<int, string>, string>, Dictionary<Dictionary<int, string>, Dictionary<int, string>>></code>を返す<code>NegativeMethod</code>という関数があるとしよう。</p> <p>これも<code>var</code>を使うと型名を書かなくてよい。</p> <pre><code class="csharp">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(); </code></pre> <p>上記のようなコードが、下記のように書ける。</p> <pre><code class="csharp">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(); </code></pre> <p>型が明確になっている場合は、複雑な型を書かなくて良くなる。<code>Tuple</code>や<code>Dictionary</code>は複雑になる場合もあるが、それをいちいち書かなくても良いメリットとなる。なお、後述するがこういう使い方にはデメリットもあるので注意。</p> <h2 id="型が変更されたときに書き直さなくても良い"><a href="#%E5%9E%8B%E3%81%8C%E5%A4%89%E6%9B%B4%E3%81%95%E3%82%8C%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AB%E6%9B%B8%E3%81%8D%E7%9B%B4%E3%81%95%E3%81%AA%E3%81%8F%E3%81%A6%E3%82%82%E8%89%AF%E3%81%84">型が変更されたときに書き直さなくても良い</a></h2> <p>たとえば<code>userId</code>は<code>int</code>型だったが、アルファベットを含めるという仕様変更にあたり<code>string</code>型に変更することになったとする。</p> <p>ここで、下記のように修正する必要がある。</p> <pre><code class="csharp">// GenerateUserIdはintを返す int userId = GenerateUserId(); // ▲これを下記のように変更する▼ // GenerateUserIdはstringを返すようになった string userId = GenerateUserId(); </code></pre> <p>数か所であれば問題ないがもし何十箇所・何百箇所も記載してあればそれらを漏れなく修正する必要がある。</p> <p>一括で置換するという方法もない訳ではないが、対象が漏れなく置換されたか、本来修正範囲外のコードが変更されていないかなどの差分確認の作業が結局発生する。</p> <p>初めから<code>var</code>で記載しておけば型が変更されてもコードの修正が必要なく、修正後にテストを走らせればそれだけで済む。</p> <pre><code class="csharp">// GenerateUserIdがintからstringになっても、ここは修正する必要がない var userId = GenerateUserId(); </code></pre> <h2 id="コードが読みやすくなる"><a href="#%E3%82%B3%E3%83%BC%E3%83%89%E3%81%8C%E8%AA%AD%E3%81%BF%E3%82%84%E3%81%99%E3%81%8F%E3%81%AA%E3%82%8B">コードが読みやすくなる</a></h2> <p>ここは感覚的な問題だが例を示す。</p> <p>下記のようなコードがあるとする。</p> <pre><code class="csharp">int userId = GenerateUserId(); string firstName = ""; string lastName = ""; DateTime birthday = new DateTime(1990, 1, 1); </code></pre> <p>これは<code>var</code>を使用すると次のように書ける。</p> <pre><code class="csharp">var userId = GenerateUserId(); var firstName = ""; var lastName = ""; var birthday = new DateTime(1990, 1, 1); </code></pre> <p>こうすると型の部分が全て<code>var</code>になり、変数名のインデントが揃って読みやすくなる…気がする。少なくとも私は、バラバラに型を書いているより<code>var</code>で揃っていた方が読みやすい。</p> <h1 id="デメリット"><a href="#%E3%83%87%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88">デメリット</a></h1> <p>上記のようにとてもメリットの大きな<code>var</code>だが、デメリットとなるケースも存在する。</p> <p>それは、人間が容易に型を推論できない場合だ。</p> <pre><code class="csharp">var firstName = GetFirstName(userId); </code></pre> <p>上記の場合、おそらく<code>firstName</code>は<code>string</code>型になるだろうという想像が出来る。<code>var</code>を使用するのが相応しいケースの一つだ。</p> <p>しかし下記の場合はどうだろう?</p> <pre><code class="csharp">var idAndNames = GetIdAndNames(); </code></pre> <p><code>GetIdAndNames</code>はおそらく<code>id</code>と<code>name</code>を(おそらくペアで)取得するメソッドだと予想はできるが、どういう型になっているかは実装部分を見ないと判定できない。<code>Dictionary<int, string></code>かもしれないし<code>List<Tuple<int, string>></code>かもしれない。独自クラスのコレクションになっている可能性もある。</p> <p><code>var</code>を使用したら<code>GetIdAndNames</code>がどのような型を返すとしても寛容に受け入れてしまう反面、型が分かりにくくなるというデメリットもある。(上記の例は関数名などのネーミングの問題もあるが)</p> <p>Visual StudioなどのIDE上で読むのであれば、変数名にマウスオーバーしたら型が分かるが、バージョン管理ソフトの履歴などの画面では当然そのような機能がないため読みづらい。型が分かりにくい場合は型を明記するが、コメントを添えておくと良いだろう。</p> <p>コメントは後で型が変わった時などにメンテしなければならないので、明記する方が個人的には良いと思う。型を明記していればコンパイルエラーなどで検知できるので修正漏れを防ぐ助けにもなる。</p> <pre><code class="csharp">// varを使わず型を明記する場合 Dictionary<int, string> = GetIdAndNames(); // コメントを添える場合 // GetIdAndNamesはDictionary<int, string> var idAndNames = GetIdAndNames(); </code></pre> <h1><code>var</code>は使うべきか</h1> <p>これはもちろんチームのコーディング規約や方針に従わなければならないが、少なくとも私は個人開発では積極的に利用する。私がアサインされたチームでも今のところ「<code>var</code>は禁止」というところはなかったので非常に助かっている。</p> <p>Microsoftの<a target="_blank" rel="nofollow noopener" href="https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/inside-a-program/coding-conventions">C# のコーディング規則 (C# プログラミング ガイド)</a>にも、</p> <blockquote> <p>変数の型が割り当ての右側から明らかである場合、または厳密な型が重要でない場合は、ローカル変数の暗黙の型指定を使用します。</p> </blockquote> <p>と明記されている。</p> あぱしょに