C#を用いたソフトウェア開発において、ソースコードの可読性と生産性を向上させるために欠かせない機能の一つが「var」キーワードによる型推論です。

C# 3.0で導入されて以来、モダンなコーディングスタイルには不可欠な要素となりましたが、その自由度の高さゆえに「どこまでvarを使うべきか」という議論が絶えません。

適切にvarを活用することで、冗長な記述を排除し、ロジックの本質に集中できる美しいコードを記述できます。

一方で、誤った使い方をすると、コードの意図が不透明になり、メンテナンス性を著しく低下させるリスクも孕んでいます。

本記事では、プロのテクニカルライターの視点から、varの基本的な使い方から、具体的なメリット・デメリット、そして現場で役立つ「型推論を使い分けるための判断基準」までを徹底的に解説します。

C#のvarとは何か?型推論の基本概念

C#におけるvarは、「暗黙的に型指定されたローカル変数」を宣言するためのキーワードです。

本来、C#は静的型付け言語であり、変数を宣言する際にはその型(intstringなど)を明示する必要があります。

しかし、varを使用すると、代入される右辺の値に基づいて、コンパイラが自動的に型を決定してくれます。

ここで重要なのは、varはJavaScriptやPythonのような動的型付け(実行時に型が決まるもの)ではないという点です。

あくまでコンパイル時に型が確定しており、一度型が決まれば、後から別の型の値を代入することはできません。

varの基本的な記述方法

まずは、基本的なvarの使用例を見てみましょう。

右辺の型が明らかな場合、型名を繰り返す必要がなくなります。

C#
using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        // 型名を明示的に指定する場合
        string message1 = "Hello, C#!";
        
        // varを使用する場合(コンパイラがstringだと推論する)
        var message2 = "Hello, C#!";

        // 複雑な型での利用
        Dictionary<int, List<string>> complexMap = new Dictionary<int, List<string>>();
        
        // varを使うと記述がスッキリする
        var complexMapWithVar = new Dictionary<int, List<string>>();

        Console.WriteLine($"Message: {message2}");
        Console.WriteLine($"Type of complexMapWithVar: {complexMapWithVar.GetType().Name}");
    }
}
実行結果
Message: Hello, C#!
Type of complexMapWithVar: Dictionary`2

上記の例のように、varを使うことで、特にジェネリクスを含む複雑な型名を何度も書く手間が省けます。

varを使用するための必須条件と制限事項

varは何にでも使えるわけではありません。

C#の言語仕様として、いくつかの厳格な制約が存在します。

これらを正しく理解していないと、コンパイルエラーの原因となります。

1. ローカル変数にのみ使用可能

varを使用できるのは、メソッド内で宣言されるローカル変数のみです。

クラスのフィールド(メンバ変数)、メソッドの引数の型、戻り値の型としてvarを使用することはできません。

2. 宣言と同時に初期化が必要

コンパイラは右辺の値を見て型を推論するため、宣言と同時に必ず値を代入(初期化)しなければなりません。

C#
// エラー例
var score; // 初期化されていないためエラー
score = 100;

3. nullで初期化することはできない

nullには特定の型情報がないため、varに直接nullを代入して宣言することはできません。

ただし、型キャストを行えば可能ですが、それなら最初から型を明示した方が賢明です。

4. 複数の変数を一行で宣言できない

int a = 1, b = 2; のような記述は可能ですが、varを用いた場合は複数宣言は許可されていません。

varを利用するメリット

varを積極的に活用することには、単に「文字数が減る」以上の大きな利点があります。

コードの簡潔性と可読性の向上

最も大きなメリットは、ソースコードのノイズを減らせることです。

特に長い型名を持つクラスや、ジェネリクスを多用するコレクションを扱う場合、左右に同じ型名が並ぶのは冗長です。

C#
// 冗長な例
CustomerManagementServiceProxy proxy = new CustomerManagementServiceProxy();

// スッキリした例
var proxy = new CustomerManagementServiceProxy();

後者の方が、変数の役割(proxyであること)が際立ち、コードの意図が読み取りやすくなります。

匿名型のサポート

C#において、var必須となる場面があります。

それが「匿名型」を使用する場合です。

LINQなどで一時的に特定のプロパティだけを持つオブジェクトを作りたい場合、その型には名前がないため、varでしか受け取ることができません。

C#
var userInfo = new { Name = "田中", Age = 30 };
Console.WriteLine($"{userInfo.Name}さんは{userInfo.Age}歳です。");

リファクタリングの容易性

例えば、メソッドの戻り値の型を List<int> から int[] に変更した場合、呼び出し側で var を使っていれば、受け取り側のコードを修正する必要がありません。

変更に強い柔軟なコードを書く上で、型推論は大きな助けとなります。

varを利用するデメリットと注意点

一方で、無秩序にvarを使用すると、コードの品質を下げてしまう懸念があります。

型の透明性が失われる

右辺がメソッド呼び出しの場合、その戻り値の型が何であるかがコードを一見しただけでは分からなくなります。

C#
// これは何の型が返ってくるのか?
var data = repository.GetData();

統合開発環境(IDE)を使っていればマウスホバーで確認できますが、GitHub上のコードレビューや差分確認の際、あるいは印刷されたコードを読む際などには、「型がわからない」ことが大きなストレスになります。

意図しない型の推論

数値リテラルなどを扱う場合、意図しない型として推論されるリスクがあります。

C#
var value = 10 / 3; // これは int 型(結果は 3)

もし、小数点以下を期待して double を意図していたとしても、右辺が整数同士の演算であれば int になってしまいます。

このように、リテラルの型に依存する性質を理解していないとバグの原因になります。

型推論を適切に使い分けるための判断基準

varを使うべきか、明示的な型を使うべきか。

その判断基準は、「その型が右辺から一目で判別できるか」に集約されます。

varを使うべきケース

1. new演算子でインスタンス化する場合

右辺にクラス名が記述されているため、型は明白です。

C#
var users = new List<User>();
var logger = new FileLogger("log.txt");

2. キャストが明示されている場合

右辺でキャストを行っているなら、型を重ねて書く必要はありません。

C#
var manager = (Employee)context.Find("id");

3. LINQのクエリ結果を受け取る場合

LINQの戻り値は IEnumerable<T>IQueryable<T> など複雑になりがちです。

また、匿名型を扱うことも多いため、原則として var を使用します。

C#
var activeUsers = users.Where(u => u.IsActive).OrderBy(u => u.Name);

型を明示すべきケース

1. 基本データ型(int, string, boolなど)のリテラル

基本データ型の場合、varを使っても文字数の節約効果は薄く、むしろ明示されていた方が直感的です。

C#
// 推奨
int count = 10;
string title = "Settings";

// 非推奨(あえてvarを使う必要性が低い)
var count = 10;

2. 戻り値の型が不明瞭なメソッド呼び出し

メソッド名から型が想像できない場合は、型を明示して読み手の負担を減らします。

C#
// 推奨
User result = service.FindById(id);

// 非推奨(resultがUserなのか、Dtoなのか、IDなのか不明)
var result = service.FindById(id);

3. インターフェース型として扱いたい場合

特定のクラスではなく、インターフェースの型として変数を保持したい場合は、varを使ってはいけません。

varは常に「具体的な実装クラス」として推論されてしまうからです。

C#
// Listとしてではなく、IEnumerableとして扱いたい場合
IEnumerable<string> categories = new List<string>();

C# 9.0以降の「ターゲット型new」との比較

C# 9.0からは、新しい構文として「ターゲット型new(Target-typed new expressions)」が導入されました。

これは var とは逆のアプローチで、左辺に型を書き、右辺の new 側で型名を省略する手法です。

C#
// varを用いた場合
var list = new List<string>();

// ターゲット型newを用いた場合(C# 9.0〜)
List<string> list = new();

どちらを使うべきかは好みの問題もありますが、フィールドの宣言など var が使えない場所でも記述を簡略化できるため、現代のC#開発では「ローカル変数はvar、フィールドはターゲット型new」という使い分けが一般的になりつつあります。

実践的なサンプルコード:varの活用シーン

それでは、これまでの内容を踏まえた実践的なコード例を見てみましょう。

ビジネスロジックの中でどのように var が整理に役立つかを確認してください。

C#
using System;
using System.Collections.Generic;
using System.Linq;

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class InventoryManager
{
    public void ProcessProducts()
    {
        // 1. new演算子を伴うためvarを推奨
        var products = new List<Product>
        {
            new Product { Id = 1, Name = "Laptop", Price = 120000m },
            new Product { Id = 2, Name = "Mouse", Price = 5000m },
            new Product { Id = 3, Name = "Monitor", Price = 35000m }
        };

        // 2. LINQでの型推論(匿名型を利用)
        // 戻り値の型が複雑になるためvarが最適
        var cheapProductNames = products
            .Where(p => p.Price < 50000m)
            .Select(p => new { p.Name, DisplayPrice = $"{p.Price:C}" });

        Console.WriteLine("Affordable Items:");
        foreach (var item in cheapProductNames)
        {
            // itemの型はコンパイル時に確定している
            Console.WriteLine($"- {item.Name} ({item.DisplayPrice})");
        }

        // 3. 型を明示すべきケース
        // メソッド名だけでは型が分かりにくいため明示する
        decimal totalPrice = CalculateTotal(products);
        Console.WriteLine($"Total: {totalPrice:C}");
    }

    private decimal CalculateTotal(List<Product> products)
    {
        return products.Sum(p => p.Price);
    }
}

public class Program
{
    public static void Main()
    {
        var manager = new InventoryManager();
        manager.ProcessProducts();
    }
}
実行結果
Affordable Items:
- Mouse (¥5,000)
- Monitor (¥35,000)
Total: ¥160,000

このコードでは、List<Product> のインスタンス化やLINQのクエリ結果には var を使い、計算結果を受け取る decimal 型には明示的な型指定を行っています。

これにより、「どこに注目すべきか」が明確なコードになっています。

varに関するよくある疑問(FAQ)

全てのローカル変数をvarにしても良いですか?

理論上は可能ですが、推奨されません。

Microsoftのコーディングガイドラインでは、型が右辺から明らかな場合にのみ var を使用することを推奨しています。

全ての変数を var にすると、ソースコードを静的に解析(コードリーディング)する際の速度が著しく低下します。

varを使うと実行速度が遅くなりますか?

いいえ、実行速度は全く変わりません。

var はコンパイル時に具体的な型に置き換えられます。

生成される中間言語(IL)は型を明示した場合と全く同じであるため、実行時のパフォーマンスに影響を与えません。

dynamicとの違いは何ですか?

var は「静的型付け」であり、コンパイル時に型が決まります。

一方、dynamic は「動的型付け」であり、実行時に型が決まります。

dynamic を使用するとコンパイル時の型チェックが行われなくなるため、全く別物として扱う必要があります。

通常、C#で dynamic を使うのは COM 操作やリフレクションなどの特殊なケースに限定されます。

まとめ

C#の var は、正しく使えば開発効率とコードの可読性を劇的に向上させる強力な武器となります。

しかし、その魔法に頼りすぎてコードの透明性を損なわないよう注意が必要です。

本記事で解説した内容をまとめると以下の通りです。

  • varの正体:コンパイル時に型が確定する静的型付け(型推論)。
  • メリット:冗長なコードの削減、リファクタリングの耐性、匿名型の利用。
  • デメリット:右辺が不明瞭な場合の可読性低下、意図しない型推論。
  • 判断基準「右辺を見て型が即座に判断できるか」を基準にする。

モダンなC#開発においては、new 演算子やLINQ、匿名型には積極的に var を使い、基本データ型や複雑なロジックの結果を受け取る際には明示的な型指定を行うという「ハイブリッドな使い分け」がベストプラクティスです。

チームで開発している場合は、コーディング規約を策定し、var の使用範囲を統一することも検討してください。

一貫性のある美しいコードは、長期的なプロジェクトの成功に大きく貢献します。

この記事を参考に、ぜひあなたのプロジェクトでも適切な型推論の活用を実践してみてください。