【C#入門】varキーワードの基本と注意点をサンプルコードで学ぶ
はじめに
C#の学習を始めると、多くのサンプルコードで var
というキーワードに出会うことでしょう。
csharp
var message = "Hello, World!";
var count = 100;
一見すると、この var
はどんな種類のデータでも入れられる「魔法の箱」のように見えるかもしれません。PythonやJavaScriptといった動的型付け言語の経験がある方なら、それらと同じようなものだと感じるかもしれません。
しかし、それは大きな誤解です。C#における var
は、静的型付け言語の原則を維持したまま、開発者のコーディングを助けてくれる非常に便利な「型推論」機能なのです。
この記事では、C#入門者から中級者へとステップアップを目指すあなたのために、var
キーワードの正体から、そのメリット、具体的な使い方、そして陥りがちな注意点まで、豊富なサンプルコードと共に徹底的に解説します。
この記事を読み終える頃には、あなたは var
を「なんとなく」使うのではなく、「意図を持って」正しく、効果的に使いこなせるようになっているはずです。モダンで読みやすいC#コードを書くための第一歩として、var
の世界を一緒に探検していきましょう。
第1章: var
キーワードとは? – 型推論の基本
まず最初に、var
の最も重要な核心部分を理解しましょう。
1. var
の正体: 型推論 (Type Inference)
var
は、それ自体がデータ型ではありません。var
は「ここに入る変数の型を、コンパイラ(プログラムを機械が読める言葉に翻訳する翻訳機)が右辺の値から推論して、自動的に決定してください」と指示するためのキーワードです。この仕組みを型推論 (Type Inference) と呼びます。
次のコードを見てみましょう。
csharp
// var を使った宣言
var number = 10;
var name = "Taro Yamada";
var pi = 3.14;
このコードがコンパイルされるとき、C#コンパイラは次のように解釈します。
-
var number = 10;
- 右辺の
10
は整数リテラルなので、number
変数の型はint
だな。 - 結果:
int number = 10;
と書いたのと同じ意味になる。
- 右辺の
-
var name = "Taro Yamada";
- 右辺の
"Taro Yamada"
は文字列リテラルなので、name
変数の型はstring
だな。 - 結果:
string name = "Taro Yamada";
と書いたのと同じ意味になる。
- 右辺の
-
var pi = 3.14;
- 右辺の
3.14
は浮動小数点リテラルなので、pi
変数の型はdouble
だな。 - 結果:
double pi = 3.14;
と書いたのと同じ意味になる。
- 右辺の
つまり、var
を使って宣言された変数は、コンパイルの時点で型が完全に確定します。これを静的型付け (Statically Typed) と言います。一度 int
型と推論された number
変数に、後から文字列を代入しようとすると、コンパイルエラーが発生します。
csharp
var number = 10; // ここで number は int 型に確定
number = "hello"; // エラー! CS0029: 型 'string' を 'int' に暗黙的に変換できません。
これは、C#の安全性を支える非常に重要な特徴です。var
はこの静的型付けのルールを一切壊しません。実行時のパフォーマンスも、型を明示的に書いた場合と全く同じです。var
は、あくまで開発者が書くコードをシンプルにするための「シンタックスシュガー(糖衣構文)」なのです。
2. dynamic
との決定的な違い
C#には dynamic
というキーワードもあります。これは var
とは全くの別物です。
var
(静的型付け): コンパイル時に型が決定する。型が持つメンバー(メソッドやプロパティ)しか呼び出せず、間違った呼び出しはコンパイルエラーになる。dynamic
(動的型付け): 実行時まで型の決定が遅延される。コンパイル時には型チェックが行われず、実行時にメンバーが存在しないと実行時エラー(RuntimeBinderException
)が発生する。
“`csharp
// var の例 (静的型付け)
var staticValue = “hello”;
// Console.WriteLine(staticValue.Length); // OK. string型にはLengthプロパティがある
// Console.WriteLine(staticValue.Foo()); // コンパイルエラー! string型にFooメソッドはない
// dynamic の例 (動的型付け)
dynamic dynamicValue = “hello”;
Console.WriteLine(dynamicValue.Length); // 実行時OK.
Console.WriteLine(dynamicValue.Foo()); // コンパイルは通るが、実行時にエラー!
“`
dynamic
は、COM相互運用や、Pythonなどの動的言語との連携といった特殊なシナリオで使われます。通常のアプリケーション開発で var
の代わりに dynamic
を使う理由はほとんどありません。var
は安全で、dynamic
はリスクを伴う、と覚えておきましょう。
3. なぜvar
を使うのか? – var
のメリット
では、なぜわざわざ var
を使うのでしょうか?それにはいくつかの明確なメリットがあります。
メリット1: コードの簡潔さ
最も分かりやすいメリットは、コードが短く、シンプルになることです。特に、型名が長くなる場合にその威力は絶大です。
例えば、キーが文字列で、値が「整数のリスト」であるディクショナリを考えてみましょう。
“`csharp
// 型を明示する場合
Dictionary
// var を使う場合
var userScores = new Dictionary
“`
どちらが読みやすいかは一目瞭然です。var
を使うことで、繰り返し同じ型名を書く必要がなくなり、コードのノイズが減ります。
メリット2: 可読性の向上
「コードが短くなるのは分かったけど、型が分からないと逆に読みにくくない?」と感じるかもしれません。これはもっともな意見です。しかし、多くの場合、var
は可読性を向上させます。
その理由は、変数の「使われ方」や「作られ方」に意識を集中できるからです。
csharp
// 右辺を見れば型は明らか
var customer = new Customer();
var products = GetAllProducts(); // メソッド名から製品リストだと分かる
var name = customer.Name;
上記のコードでは、右辺の new Customer()
やメソッド名 GetAllProducts()
から、変数がどのようなものであるかが明確に分かります。型名を明記しなくても、コードの意味を理解するのに支障はありません。むしろ、重要な情報である「何をしているか(new
やメソッド呼び出し)」に目が向きやすくなります。
メリット3: リファクタリング耐性の向上
リファクタリングとは、プログラムの外部的な振る舞いを変えずに、内部の構造を改善することです。var
はこのリファクタリングを容易にします。
例を見てみましょう。GetUser
というメソッドがあり、最初は User
クラスのインスタンスを返していたとします。
“`csharp
public class User { / … / }
public User GetUser(int id) { / … / return new User(); }
// 呼び出し側のコード
User user = GetUser(1);
“`
その後、仕様変更で、より詳細な情報を持つ UserDetails
クラスを返すように GetUser
メソッドを変更したとします。
csharp
public class UserDetails { /* ... */ }
public UserDetails GetUser(int id) { /* ... */ return new UserDetails(); }
このとき、呼び出し側のコードを User user = ...
のままにしておくと、コンパイルエラーになります。UserDetails
型を User
型の変数には代入できないからです。次のように修正が必要です。
csharp
// 呼び出し側のコードを修正する必要がある
UserDetails user = GetUser(1);
しかし、もし最初から var
を使って書いていたらどうでしょうか?
csharp
// var を使っていた場合
var user = GetUser(1);
このコードは、GetUser
メソッドの戻り値が User
から UserDetails
に変わっても、一切修正する必要がありません。var
が新しい戻り値の型 UserDetails
を正しく推論してくれるからです。このように、var
は変更に強い、柔軟なコードを書く手助けをしてくれます。
第2章: var
の具体的な使い方 – 実践的なサンプルコード
var
の基本とメリットが分かったところで、次は実際のコードでどのように使われるかを見ていきましょう。
1. 基本的なデータ型での使用
これは第1章で見た通り、最も基本的な使い方です。
“`csharp
// 整数
var integerValue = 123; // int
// 浮動小数点数
var doubleValue = 123.45; // double
var floatValue = 123.45f; // float (fサフィックスが必要)
var decimalValue = 123.45m; // decimal (mサフィックスが必要)
// 文字列
var stringValue = “こんにちは、世界!”; // string
// 真偽値
var boolValue = true; // bool
“`
Visual StudioなどのIDEを使っている場合、var
で宣言した変数にマウスカーソルを合わせると、推論された型が表示されます。ぜひ試してみてください。
2. オブジェクトのインスタンス化
new
キーワードを使ってクラスのインスタンスを生成する際は、var
の利用が特に推奨されます。右辺で型名を記述しているため、左辺でそれを繰り返すのは冗長だからです。
“`csharp
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
// var を使ったインスタンス化
var person = new Person(“Taro”, 30);
// 型を明示した場合(冗長に感じる)
Person person2 = new Person(“Hanako”, 25);
``
var` を使うべき」と多くのC#コーディング規約で定められているほど、一般的で優れた使い方です。
このパターンは「
3. LINQとの組み合わせ
var
が最も輝く場面の一つが、LINQ (Language-Integrated Query) を使うときです。LINQは、データコレクションに対してSQLのような問い合わせ(クエリ)を書くことができる機能です。
LINQのクエリ結果、特に select
句で新しいオブジェクトを作成した場合、その結果は匿名型 (Anonymous Type) となることがあります。匿名型とは、その場で一時的に作られる、名前のない型のことです。
“`csharp
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
var customers = new List
{
new Customer { Id = 1, Name = “Alice”, City = “Tokyo” },
new Customer { Id = 2, Name = “Bob”, City = “Osaka” },
new Customer { Id = 3, Name = “Charlie”, City = “Tokyo” }
};
// LINQクエリ: 東京在住の顧客の名前とIDを取得する
var tokyoCustomers = from c in customers
where c.City == “Tokyo”
select new { CustomerName = c.Name, CustomerId = c.Id };
“`
このとき、tokyoCustomers
の型は何でしょうか? select new { ... }
によって作られたのは匿名型であり、CustomerName
(string) と CustomerId
(int) というプロパティを持つ、この場所でしか使えない特別な型です。私たちはこの型の名前を知りませんし、書くこともできません。
ここで var
が必須となります。var
を使うことで、コンパイラがこの複雑な匿名型を正しく推論し、tokyoCustomers
変数に割り当ててくれます。
この結果をループで処理する際も var
が役立ちます。
csharp
foreach (var customerInfo in tokyoCustomers)
{
// customerInfo は匿名型。プロパティにアクセスできる。
Console.WriteLine($"ID: {customerInfo.CustomerId}, Name: {customerInfo.CustomerName}");
}
もし var
がなければ、LINQの強力な機能の多くは実現不可能だったでしょう。
4. foreach
ループでの使用
LINQに限らず、一般的な foreach
ループでも var
は非常に便利です。コレクションに含まれる要素の型を明記する必要がなくなります。
“`csharp
var names = new List
var scores = new Dictionary
// List
foreach (var name in names)
{
// name は string 型と推論される
Console.WriteLine(name.ToUpper());
}
// Dictionary
foreach (var score in scores)
{
// score は KeyValuePair
Console.WriteLine($”Subject: {score.Key}, Score: {score.Value}”);
}
``
var` を使うことで、一貫性のあるシンプルなループを記述できます。
このように、コレクションの型が何であれ
5. using
ステートメントでの使用
ファイルストリームやデータベース接続など、使い終わったら必ずリソースを解放(Dispose
メソッドを呼ぶ)する必要があるオブジェクトがあります。これを安全に行うのが using
ステートメントです。この using
ステートメントでも var
を使えます。
“`csharp
using System.IO;
// using でストリームリーダーを生成
// reader は StreamReader 型と推論される
using var reader = new StreamReader(“myFile.txt”);
string content = reader.ReadToEnd();
Console.WriteLine(content);
// using ブロックを抜けるときに自動的に reader.Dispose() が呼ばれる
``
new
これもと組み合わせるパターンなので、
var` の利用が推奨されます。
第3章: var
を使う上での注意点とルール
var
は非常に便利ですが、万能ではありません。使えない場面や、使うべきでない場面が存在します。これらを理解することが、var
を正しく使いこなす鍵となります。
1. var
が使えない場面
以下のケースでは、var
を使うことができず、コンパイルエラーになります。
ルール1: 宣言と同時に初期化が必須
var
は右辺の値から型を推論するため、宣言時に右辺の値(初期化子)がなければ型を決定できません。
“`csharp
// NG: 初期化されていないため、型を推論できない
var myVariable; // エラー CS0818: 暗黙的に型指定された変数は初期化されなければなりません
// OK
var myVariable = 10;
“`
ルール2: null
での初期化は不可(C# 9以前)
null
は「何もない」ことを示すリテラルで、それ自体は特定の型を持ちません。参照型(string
やクラスなど)にも、Null許容値型(int?
など)にも代入できます。そのため、コンパイラは null
から特定の型を一つに絞り込むことができません。
csharp
// NG (C# 9以前): null から型を推論できない
var myObject = null; // エラー CS0815: 暗黙的に型指定されたローカルを null に初期化することはできません
補足: C# 10以降では、プロジェクトの設定でNull許容参照型が有効になっている場合、var x = null;
は object? x = null;
と解釈されることがあります。しかし、意図が不明確になりがちなので、null
で初期化したい場合は string? myString = null;
のように型を明示するのが一般的です。
ルール3: メソッドの戻り値の型や引数の型には使えない
メソッドのシグネチャ(名前、引数、戻り値の型)は、そのメソッドの「契約」を定義するものです。外部から見て型が明確でなければならないため、var
で曖昧にすることは許されません。
“`csharp
// NG: メソッドの戻り値の型には使えない
public var MyMethod() // エラー
{
return “hello”;
}
// NG: メソッドの引数の型には使えない
public void AnotherMethod(var parameter) // エラー
{
// …
}
“`
ルール4: クラスのフィールドには使えない
var
はローカル変数(メソッド内で宣言される変数)でのみ使用できます。クラスのメンバーであるフィールド(インスタンス変数や静的変数)には使用できません。
“`csharp
class MyClass
{
// NG: フィールドの宣言には var は使えない
// private var myField = “This is not allowed.”; // エラー CS0825
public void MyMethod()
{
// OK: ローカル変数の宣言には var は使える
var myLocalVariable = "This is allowed.";
}
}
“`
これは、C#のコンパイルの仕組みに関係しています。クラスのメンバーは、メソッド本体がコンパイルされるより前に型が確定している必要があるため、型推論に頼ることができないのです。
2. var
を使うべきでない場面 – 可読性を損なうケース
技術的にはvar
を使えるけれど、使わない方が良い(コードが分かりやすくなる)場面もあります。これは絶対的なルールではなく、チームや個人のコーディングスタイルによりますが、一般的に考慮すべきガイドラインです。
ケース1: 右辺から型が自明でない場合
var
の大原則は「右辺を見れば型が分かる」ことです。逆に言えば、右辺を見ても型が分かりにくい場合は、var
を使うべきではありません。
“`csharp
// 悪い例: GetValue() が何を返すか、この1行だけでは分かりにくい
// int? long? double? それともカスタム型?
var result = GetValue();
// 良い例: 型を明示することで、メソッドの戻り値の型が明確になる
int count = GetCount();
string name = GetName();
“`
メソッド名が GetCustomerById
のように戻り値を強く示唆している場合は var
でも問題ありませんが、ProcessData
や Calculate
のような汎用的な名前の場合は、型を明示する方が親切です。
ケース2: 数値リテラルの型を意図的に制御したい場合
C#の数値リテラルには、デフォルトの型があります。
10
->int
10.5
->double
var
を使うと、このデフォルトの型が推論されます。
csharp
var price = 100; // int 型
var weight = 75.5; // double 型
しかし、金融計算などで高精度な計算が必要な decimal
型や、メモリを節約したい場合の float
型を使いたい場合、var
は意図しない型を招く可能性があります。
“`csharp
// 意図: 金額なので decimal 型を使いたい
// 悪い例: var を使うと double 型になってしまう!
var money = 120.50; // money は double 型になる
// 良い例: mサフィックスで decimal であることを明示する
var moneyDecimal = 120.50m; // moneyDecimal は decimal 型になる
// さらに良い例: 型を明示することで、意図がより明確になる
decimal moneyExplicit = 120.50m;
“`
特に double
と decimal
は内部的な表現が全く異なり、計算誤差の挙動も変わるため、非常に重要な違いです。このような場合は、var
に頼らず、型を明記する方が安全で、コードの意図も明確になります。
結論として、var
を使うかどうかの判断基準は「コードの可読性」です。 自分やチームのメンバーが、数ヶ月後にそのコードを読んだときに、一瞬で意味を理解できるのはどちらの書き方か? を常に考えるようにしましょう。
第4章: var
にまつわる発展的なトピック
最後に、var
に関連する少し発展的なトピックをいくつか紹介します。
1. ターゲット型のnew
式 (C# 9.0以降)
C# 9.0から、var
とは逆のアプローチが導入されました。それがターゲット型の new
式です。
これは、左辺の変数の型が分かっている場合に、右辺の new
式で型名を省略できる機能です。
“`csharp
// 従来の var
var person1 = new Person(“Taro”, 30);
// ターゲット型の new 式
Person person2 = new(“Hanako”, 25); // new Person(…) の Person を省略
``
var
これにより、を使うか、ターゲット型の
new式を使うか、開発者が好みのスタイルを選べるようになりました。フィールドの初期化のように
var` が使えない場面では、後者が特に役立ちます。
csharp
class MyClass
{
// フィールドの初期化では var は使えないが、ターゲット型のnew式は使える
private List<string> _names = new();
}
2. var
とラムダ式、メソッドグループ
ラムダ式やメソッドグループは、それ単体では特定のデリゲート型(Action
やFunc<T>
など)に確定しません。複数の互換性のあるデリゲート型に変換できる可能性があります。var
は型を一つに絞り込めないため、これらを直接 var
変数に代入することはできません。
“`csharp
// NG: ラムダ式は Action か Func か、あるいは他のデリゲートか判断できない
var myAction = () => Console.WriteLine(“Hello”); // エラー
// NG: メソッドグループも同様
var myPrinter = Console.WriteLine; // エラー
// OK: キャストして型を明示すれば var を使える
var myActionOk = (Action)(() => Console.WriteLine(“Hello”));
var myPrinterOk = (Action
// OK: もちろん、最初から型を明示するのが最もシンプル
Action myActionSimple = () => Console.WriteLine(“Hello”);
Action
``
var` はコンパイラが推論に迷うような曖昧な状況では使えない」という原則を示しています。
このルールは、「
まとめ
長くなりましたが、C#の var
キーワードについて、その本質から応用までを詳しく見てきました。最後に、重要なポイントをまとめておさらいしましょう。
-
var
は型推論:var
は、コンパイラが右辺から変数の型を推論し、自動で設定してくれる機能です。動的型付けのdynamic
とは全くの別物で、C#の静的型付けの安全性を損ないません。 -
var
のメリット:- 簡潔さ: 長い型名を繰り返し書く手間を省き、コードをスッキリさせます。
- 可読性: 右辺の処理に集中でき、何が行われているかを理解しやすくなります。
- 柔軟性: リファクタリング時に、メソッドの戻り値の型変更などに強くなります。
-
var
を使うべき時:new
を使ったインスタンス化 (var p = new Person();
)- LINQのクエリ結果、特に匿名型を扱う時
- 右辺のメソッド呼び出しなどから型が自明な時 (
var name = customer.GetName();
) foreach
,using
ステートメント内
-
var
を避けるべき時(または注意すべき時):- 右辺から型が分かりにくい場合 (
var result = ProcessData();
) - 数値リテラルの型(
int
vsdouble
vsdecimal
)を厳密に制御したい場合 - コードを読む人にとって、型を明示した方が親切だと判断される場合
- 右辺から型が分かりにくい場合 (
-
var
が使えない場面:- 宣言のみで初期化しない場合
null
での初期化(基本的に避けるべき)- メソッドの戻り値や引数の型
- クラスのフィールド
var
は、現代のC#プログラミングにおいて必須のツールです。しかし、それは決して思考停止して使うべきものではありません。「なぜここで var
を使うのか?」「型を明示した方が分かりやすくないか?」と常に自問自答することが、質の高いコードを書く上で非常に重要です。
この記事が、あなたの var
に対する理解を深め、より良いC#コードを書くための一助となれば幸いです。Happy Coding