C#のvar
は「なんでも入る箱」ではありません。
右辺の情報からコンパイル時に具体的な型が決まるため、コードを簡潔にしつつ型安全を保てます。
本記事では、初心者が迷いがちな場面に焦点を当て、型推論の基本、便利な使い方、避けるべきケース、そして実践の指針を丁寧に解説します。
varと型推論の基本(C#初心者向け)
varは「型を省略」してもコンパイル時に型が決まる
var
で宣言すると、右辺の式から型が推論されます。
推論された型は通常の明示的な型と同じく静的な型で、コンパイル後に変わりません。
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
は右辺から型を推論するため、必ず初期化を同時に行う必要があります。
// var x; // コンパイルエラー: 初期化が必要
var x = 10; // int に推論される
var text = "abc"; // string に推論される
varで決まった型は後から変えられない(暗黙的に固定)
var
で一度決まった型は、別の型に変更できません。
同じ型なら再代入は可能です。
var n = 100; // int に推論
n = 200; // OK(どちらも int)
// n = "200"; // コンパイルエラー: string は代入不可
実際の型を確認する方法(IDEのヒント)
日常ではIDEが型を教えてくれます。
Visual StudioやVS Codeでは、カーソルを変数に重ねるとツールチップで推論結果の型が表示されます。
加えて、実行時の型名を確認したいならGetType()
が使えます。
var now = DateTime.Now; // DateTime に推論される
Console.WriteLine(now.GetType().Name); // 実行時型名を表示
DateTime
varの使い方(基本パターン)
newで型が明確なときに使う
右辺がnew 型名(...)
のときは型が明白です。
冗長な左辺の型名を省けます。
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
でスッキリ書けます。
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
を使うと読みやすくなります。
using System;
class Program
{
static void Main()
{
var text = "C#";
foreach (var ch in text) // ch は char に推論
{
Console.WriteLine(ch);
}
}
}
C
#
メソッド戻り値の型が明らかなとき
メソッド名や文脈から戻り値の型が明白な場合はvar
が有効です。
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
が必須です。
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
サフィックスを付けます。
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()
のような抽象的な名前だと、推論された型が読者に伝わりづらくなります。
// 悪い例(読み手に型が伝わりにくい)
var result = GetData();
// 良い例(型を明示)
DataResponse result2 = GetData();
// ダミーのシグネチャ例
static DataResponse GetData() => new DataResponse();
class DataResponse {}
読みやすさを優先して明示的な型を使うのが無難です。
初期値なしの宣言はできない
var
は初期化が必須です。
初期値を後で入れる設計なら、最初から型名で宣言します。
// var value; // コンパイルエラー
string value; // OK: 後で代入する前提なら型名で宣言
value = "ready";
nullだけでは型推論できない
null
単独では型が決められません。
// var x = null; // コンパイルエラー: 型が推論できない
string? x = null; // OK: 参照型を明示
object? y = null; // OK
var s = (string)null; // 可能だが可読性が低いので避ける
varはdynamicではない(別物)
var
は静的型、dynamic
は動的束縛です。
varはコンパイル時にメンバー解決され、存在しないメンバーはコンパイルエラーになります。
// 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#コードを実現できます。