閉じる

【C#】varの使い方入門 型推論の基本と使いどころ

C#のvarは「なんでも入る箱」ではありません。

右辺の情報からコンパイル時に具体的な型が決まるため、コードを簡潔にしつつ型安全を保てます。

本記事では、初心者が迷いがちな場面に焦点を当て、型推論の基本、便利な使い方、避けるべきケース、そして実践の指針を丁寧に解説します。

varと型推論の基本(C#初心者向け)

varは「型を省略」してもコンパイル時に型が決まる

varで宣言すると、右辺の式から型が推論されます。

推論された型は通常の明示的な型と同じく静的な型で、コンパイル後に変わりません。

C#
using System;

class Program
{
    static void Main()
    {
        var message = "Hello, var"; // string に推論される
        Console.WriteLine(message.ToUpper()); // string のメソッドが呼べる

        // message = 123; // コンパイルエラー: string 変数に int は代入できない
        Console.WriteLine(message.GetType().FullName); // 実行時型の確認
    }
}
実行結果
HELLO, VAR
System.String

ここでの重要ポイントは、varは動的型付けではないということです。

右辺のリテラルや式が具体的な方に導きます。

宣言と初期化は同時に書く(右辺で型を決める)

varは右辺から型を推論するため、必ず初期化を同時に行う必要があります。

C#
// var x;            // コンパイルエラー: 初期化が必要
var x = 10;          // int に推論される
var text = "abc";    // string に推論される

varで決まった型は後から変えられない(暗黙的に固定)

varで一度決まった型は、別の型に変更できません

同じ型なら再代入は可能です。

C#
var n = 100; // int に推論
n = 200;     // OK(どちらも int)
// n = "200"; // コンパイルエラー: string は代入不可

実際の型を確認する方法(IDEのヒント)

日常ではIDEが型を教えてくれます。

Visual StudioやVS Codeでは、カーソルを変数に重ねるとツールチップで推論結果の型が表示されます。

加えて、実行時の型名を確認したいならGetType()が使えます。

C#
var now = DateTime.Now; // DateTime に推論される
Console.WriteLine(now.GetType().Name); // 実行時型名を表示
実行結果
DateTime

varの使い方(基本パターン)

newで型が明確なときに使う

右辺がnew 型名(...)のときは型が明白です。

冗長な左辺の型名を省けます。

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

class Program
{
    static void Main()
    {
        var list = new List<string>(); // List<string> に推論
        list.Add("apple");
        list.Add("banana");
        Console.WriteLine($"Count = {list.Count}");
    }
}
実行結果
Count = 2

長い型名を簡潔にしたいとき

複雑なジェネリック型は見通しが悪くなりがちです。

右辺で型が十分に読み取れるならvarでスッキリ書けます。

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

class Program
{
    static void Main()
    {
        var dict = new Dictionary<string, List<Tuple<int, string>>>();
        dict["fruits"] = new List<Tuple<int, string>>
        {
            Tuple.Create(1, "apple"),
            Tuple.Create(2, "banana")
        };

        foreach (var item in dict["fruits"])
        {
            Console.WriteLine($"{item.Item1}: {item.Item2}");
        }
    }
}
実行結果
1: apple
2: banana

foreachの変数で読みやすくする

列挙対象が明らかならforeachの変数にvarを使うと読みやすくなります。

C#
using System;

class Program
{
    static void Main()
    {
        var text = "C#";
        foreach (var ch in text) // ch は char に推論
        {
            Console.WriteLine(ch);
        }
    }
}
実行結果
C
#

メソッド戻り値の型が明らかなとき

メソッド名や文脈から戻り値の型が明白な場合はvarが有効です。

C#
using System;

class Program
{
    static void Main()
    {
        var number = int.Parse("42"); // int に推論
        var upper  = "hello".ToUpper(); // string に推論
        Console.WriteLine($"{number}, {upper}");
    }
}
実行結果
42, HELLO

匿名型ではvarが必須

匿名型は型名を持たないため、宣言にはvarが必須です。

C#
using System;

class Program
{
    static void Main()
    {
        var person = new { Name = "Taro", Age = 20 }; // 匿名型
        Console.WriteLine($"{person.Name}({person.Age})");
        // 匿名型の型名は書けないため、var 以外は不可
    }
}
実行結果
Taro(20)

varを使わないほうがよい場面(注意点)

数値の意図を明確にしたいとき(int/long/double/decimal)

数値リテラルは既定の型が決まっているため、varだと意図と異なる型になることがあります。

小数リテラルの既定はdouble、整数の既定はintです。

金額など桁落ちが困るケースではdecimalを明示するか、mサフィックスを付けます。

C#
using System;

class Program
{
    static void Main()
    {
        var a = 1;     // int
        var b = 1L;    // long (L サフィックス)
        var c = 1.0;   // double
        var d = 1m;    // decimal (m サフィックス)

        Console.WriteLine($"{a.GetType().Name}, {b.GetType().Name}, {c.GetType().Name}, {d.GetType().Name}");

        // 金額などでは型を明示すると意図が伝わる
        decimal price = 1980m; // 明示的に decimal
        Console.WriteLine(price);
    }
}
実行結果
Int32, Int64, Double, Decimal
1980

誤解を避けたい場合は、型名を明示しましょう。

右辺だけでは型が読み取りづらいとき

右辺がGetData()のような抽象的な名前だと、推論された型が読者に伝わりづらくなります。

C#
// 悪い例(読み手に型が伝わりにくい)
var result = GetData();

// 良い例(型を明示)
DataResponse result2 = GetData();

// ダミーのシグネチャ例
static DataResponse GetData() => new DataResponse();
class DataResponse {}

読みやすさを優先して明示的な型を使うのが無難です。

初期値なしの宣言はできない

varは初期化が必須です。

初期値を後で入れる設計なら、最初から型名で宣言します。

C#
// var value; // コンパイルエラー
string value; // OK: 後で代入する前提なら型名で宣言
value = "ready";

nullだけでは型推論できない

null単独では型が決められません。

C#
// var x = null;          // コンパイルエラー: 型が推論できない
string? x = null;         // OK: 参照型を明示
object? y = null;         // OK
var s = (string)null;     // 可能だが可読性が低いので避ける

varはdynamicではない(別物)

varは静的型、dynamicは動的束縛です。

varはコンパイル時にメンバー解決され、存在しないメンバーはコンパイルエラーになります。

C#
// var は静的型
var text = "hello";
// text.NotExists(); // コンパイルエラー: string に存在しない

// dynamic は実行時に解決(コンパイルは通るが、実行時エラーの可能性)
dynamic d = "hello";
// d.NotExists(); // 実行時に RuntimeBinderException などが発生

安全性と補完の利便性を優先するなら var、動的な相互運用が必要な特殊ケースのみdynamicを検討します。

初心者向けベストプラクティス(使いどころの指針)

右辺で型が一目で分かるならvarを使う

右辺が明快な型情報を含むときにvarは読みやすさを高めます

new 型名(...)、明確なリテラル、よく知られた戻り値などが該当します。

読みやすさが下がるなら明示的な型名を書く

メソッド名やコンテキストから型が推測しづらい場合は、可読性のために型名を明示します。

レビューや保守を楽にします。

コーディング規約に合わせて統一する

チームでは統一された規約が重要です。

例えば「右辺がnewやリテラルならvarを使う」「公開APIでは型名を明示する」など、プロジェクトの方針に従いましょう。

変数名で意図を伝える(型名に頼りすぎない)

良い変数名は型名より強力です。

var xではなくvar totalPriceのように、役割が明確になる名前を選びましょう。

型がdecimalであるかは文脈や初期化子で十分に伝えられます。

以下に簡易的なまとめ表を示します。

使うとよい避けるほうがよい
右辺がnew 型名(...)で明確右辺だけでは型が想像しにくい
冗長なジェネリック型を簡潔にしたい数値の意図を厳密に示したい(特にdecimal)
foreachの要素型が明らか初期化なしで宣言したい
匿名型を受けたい(必須)null単独の初期化

まとめ

varは「型の省略記法」であり、型安全を保ったままコードを簡潔にする強力なツールです。

右辺が明快なときに使い、曖昧さや誤解の余地があるときは型名を明示する、というバランス感覚が大切です。

特に数値まわりでは既定の型の違いに注意し、金額などはdecimalを明示して意図を伝えましょう。

チームの規約に合わせて一貫性を保ち、変数名で役割を明確化すれば、読みやすく安全なC#コードを実現できます。

この記事を書いた人
エーテリア編集部
エーテリア編集部

C#の入門記事を中心に、開発環境の準備からオブジェクト指向の基本まで、順を追って解説しています。ゲーム開発や業務アプリを目指す人にも役立ちます。

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

URLをコピーしました!