閉じる

C#のvarはどこまで許される?型推論の使い分けと判断基準

C#でのコーディングでは、変数宣言にvarを使うべきか、明示的な型(intやstringなど)を書くべきかという悩みはよくあります。

本記事では、C#の型推論の仕組みを整理しながら、「どこまでvarを使ってよいか」「どこからは明示的な型にした方がよいか」という判断基準を、実務で使いやすい形で解説します。

C#のvarとは何かを正しく理解する

varは「なんでも入る箱」ではない

C#のvarは、CやC++経験者だと「型が何でも入る動的型?」という誤解をされがちですが、コンパイル時にきちんと型が決まる「静的型推論」です

C#
// これはint型の変数xを宣言しているのと同じ意味です
var x = 10;         // コンパイル時に「int x = 10;」と同等に扱われる
int y = 10;         // 上と完全に同じ型

C#のvar「書き方の省略記法」であり、動的型付け言語のように「実行時に型が変わる」わけではありません。

varが使える場所と使えない場所

varは以下のような場所で使えます。

  • メソッド内のローカル変数
  • foreachのイテレータ変数
  • usingのローカル変数

逆に、次のような場所ではvarは使えません。

  • フィールドの型
  • プロパティの型
  • メソッドの引数の型
  • メソッドの戻り値の型
C#
class Sample
{
    // フィールドではvarは使えません (コンパイルエラー)
    // var field = 10;  // ×

    int field = 10;     // ○ 明示的な型が必要

    // メソッド引数にもvarは使えません
    // void DoSomething(var value) { }  // ×

    void DoSomething(int value) { }     // ○
}

「varはメソッドの中だけで使える、省略記法」と押さえておくとよいです。

varを使うメリットとデメリット

メリット1: 冗長な型表記を減らせる

GenericsやLINQを使うと、型名が非常に長くなることがあります。

その場合、右辺を見れば型が明らかなときに、あえて左辺に長い型名を繰り返す必要はありません

C#
// 明示的な型で書いた場合
Dictionary<string, List<int>> map = new Dictionary<string, List<int>>();

// varを使うとすっきりします
var map2 = new Dictionary<string, List<int>>();

このようなケースでは、varを使うことで可読性がむしろ向上します。

メリット2: 匿名型やLINQで必須になる

匿名型はそもそも型名がありません。

そのため、varを使わないと受け取れません。

C#
// 匿名型の例
var user = new { Id = 1, Name = "Alice" };

// userの型を明示的に書くことはできません
// そのためvarが必須です

LINQのクエリ式やメソッドチェーンで中間結果が匿名型になることは多く、その場合もvarが事実上必須です。

デメリット: 型が見えにくくなるリスク

右辺から型が想像しづらい場合にvarを使うと、可読性を損ないます

C#
var result = service.Execute();      // resultの型は何か、コードだけでは分かりにくい
var data = repository.Get();         // dataの実体がイメージしづらい

// 一方、型が分かるように書けば可読性が上がります
OrderResult result2 = service.Execute();
Customer data2 = repository.Get();

「右辺のメソッド名や文脈から型がほぼ一意に想像できるか」が、var使用の大きな分岐点になります。

「どこまでvarが許されるか」の基本指針

原則1: 型が一目で分かるならvarを使ってよい

次のような場合は、varを使っても可読性を損ないません

C#
var count = 0;                       // どう見てもint
var name = "Alice";                  // どう見てもstring
var numbers = new List<int>();       // 右辺からList<int>とすぐ分かる
var customer = new Customer();       // 型名が右辺に明示されている

右辺だけで読者が即座に型を推測できる場合は、varを積極的に使っても良いと考えて問題ありません。

原則2: 型が分かりにくいときは明示的に書く

型がすぐに分からない、または「この変数はどんな性質を持っているのか」がコードから想像しにくい場合は、明示的な型を書いた方が安全です。

C#
// 型が曖昧に感じられる例
var result = service.Execute();      // resultは何者?

// より分かりやすい書き方
OperationResult result2 = service.Execute();

特に、ビジネスロジック層などで表現したい概念そのものが型名になっている場合は、型を明示した方が意図が伝わりやすくなります。

原則3: APIの境界ではvarを避ける

メソッドの引数や戻り値、インターフェイスの定義など「外部から見える境界」では、varは使えませんし、使うべきでもありません

C#
// APIのインターフェイスは型をはっきり書く
public Customer GetCustomerById(int id) { ... }

// メソッド内部のローカルではvarを使ってもよい
public Customer GetCustomerById(int id)
{
    var customer = _repository.Find(id);  // ローカルなのでvarはOK
    return customer;
}

外から見える部分は型を明示し、内部実装でのみvarを使うという分け方は、実務でも採用しやすい基準です。

具体例で見る「使い分け」パターン

コレクションやLINQを使う場合

LINQでは結果の型が非常に長くなったり、匿名型になったりします。

そのため、実務では以下のような書き方がよく使われます。

C#
var items = new List<int> { 1, 2, 3, 4, 5 };

// クエリ式
var evenQuery =
    from x in items
    where x % 2 == 0
    select x;

// メソッドチェーン
var evenList = items
    .Where(x => x % 2 == 0)
    .ToList();

ここで戻り値の型(List<int>など)が右辺から読み取れる場合はvarで問題ありません

ただし、クエリが複雑になり、意図しない型になっている可能性を疑いたい場合には、一度明示的に型を書いて確認するのも有効です。

匿名型を返すLINQの例

C#
var users = new[]
{
    new { Id = 1, Name = "Alice" },
    new { Id = 2, Name = "Bob" }
};

var filtered =
    from u in users
    where u.Id == 1
    select new { u.Id, u.Name };

このfiltered変数は匿名型のシーケンスなので、そもそもvar以外の選択肢がありません

ループ変数でのvar使用

C#
var numbers = new List<int> { 1, 2, 3 };

// どちらも意味は同じ
foreach (int x in numbers)
{
    Console.WriteLine(x);
}

foreach (var x in numbers)
{
    Console.WriteLine(x);
}

列挙対象のコレクションの型が明白であれば、foreachのvarは許容されるケースが多いです。

一方で、Dictionary<TKey, TValue>のように要素の型構造が複雑な場合、明示的な型の方が読みやすくなることもあります。

C#
var dict = new Dictionary<string, int>
{
    ["A"] = 1,
    ["B"] = 2
};

// varでも書けますが…
foreach (var kv in dict)
{
    Console.WriteLine($"{kv.Key}: {kv.Value}");
}

// 明示すると構造が分かりやすくなります
foreach (KeyValuePair<string, int> kv in dict)
{
    Console.WriteLine($"{kv.Key}: {kv.Value}");
}

悪い例から学ぶ: varの「やりすぎ」パターン

何でもかんでもvarにしてしまうケース

C#
// 例: すべてvarにしてしまったコード
var a = service.Get();
var b = a.Process();
var c = b.ToResult();
var d = c.Items;

// 何がどう処理されているのか、型の観点からは分かりにくい

このように変数名だけでは役割が曖昧なのに、型もvarで隠れていると、後から読む人にとって非常に負担になります。

C#
// 型を明示したバージョン
CustomerData customerData = service.Get();
ProcessedCustomer processed = customerData.Process();
CustomerResult result = processed.ToResult();
IReadOnlyList<CustomerItem> items = result.Items;

こちらの方が「何から何への変換なのか」が型名を通して伝わりやすくなっています

左辺と右辺が離れた場所にある場合

長い行のために改行し、右辺のタイプ情報が視覚的に離れてしまう場合も要注意です。

C#
// 一見すると型が見えにくい例
var result =
    service
        .WithOption(option)
        .Execute();

このような場合、メソッド名だけで戻り値の型がすぐに分からないなら、型を明示する方が無難です。

C#
OperationResult result =
    service
        .WithOption(option)
        .Execute();

実務でのルール策定例

チームでの「ガイドライン」サンプル

例えば以下のようなルールは、現場でもよく採用されています。

ルール例1

プリミティブ型(int, stringなど)で、右辺から型が明らかなときはvarを使ってよい。

ルール例2

ビジネス概念を表すクラス(Customer, Orderなど)は、戻り値や引数、重要なローカル変数では型を明示する。

ルール例3

匿名型およびLINQの中間結果にはvarを使う(実質必須)。

このように「var禁止」でも「var全面解禁」でもなく、文脈に応じて使い分けるのが現実的です。

サンプルコードでまとめたルール適用例

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

public class Customer { /* 顧客を表すドメインクラス */ }

public class CustomerRepository
{
    public Customer Find(int id)
    {
        // 顧客を検索する処理(ダミー)
        return new Customer();
    }

    public List<Customer> GetAll()
    {
        // 全件取得する処理(ダミー)
        return new List<Customer>();
    }
}

public class SampleService
{
    private readonly CustomerRepository _repository = new CustomerRepository();

    public void Run()
    {
        // 右辺から型が明らかなプリミティブ型はvar
        var count = 0;
        var message = "Start";

        Console.WriteLine($"{message}: {count}");

        // リポジトリの戻り値(Customer)は、ここでは型を明示
        Customer customer = _repository.Find(1);

        // コレクション取得は右辺から型が明確なためvarを使用
        var customers = _repository.GetAll();

        // LINQ結果はvar(匿名型になる場合もあるため)
        var vipCustomers = customers
            .Where(c => IsVip(c))
            .ToList();

        Console.WriteLine($"VIP count: {vipCustomers.Count}");

        // 匿名型の例(var必須)
        var projections = customers.Select(c => new
        {
            Name = c.ToString(),
            IsVip = IsVip(c)
        });

        foreach (var p in projections)
        {
            Console.WriteLine($"{p.Name}, VIP: {p.IsVip}");
        }
    }

    private bool IsVip(Customer customer)
    {
        // VIP判定ロジック(ダミー)
        return true;
    }
}

public class Program
{
    public static void Main()
    {
        var service = new SampleService();
        service.Run();
    }
}

上記のコードでは、「型が一目で分かるところはvar」「ビジネス意味を強く示したい部分は型を明示」というバランスで記述しています。

想定されるコンソール出力は次のようになります。

実行結果
Start: 0
VIP count: 0

(※ダミー実装のため実際の件数は変わります。ここでは形式のみ示しています)

まとめ

C#のvarは「どこまで許されるか」ではなく「どこで使うと読みやすくなるか」が本質です。

右辺から型が直感的に分かるときや、匿名型・LINQなどではvarを積極的に使うことで、コードを簡潔にできます。

一方で、ビジネス概念を表す重要な変数や、メソッドの戻り値が意味を持つ場面では、型を明示した方が意図が伝わりやすくなります。

「型情報で伝えたいメッセージがあるかどうか」を判断基準にしつつ、チームでガイドラインを共有しておくと、varの使い過ぎや禁止といった極端な状況を避けられます。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!