C#でプログラムを書くうえで、最初に身につけたいのが「変数の宣言」と「基本データ型」です。
本記事では、int・string・double・boolの使い方を中心に、宣言方法、初期化、型推論、定数、スコープ、よくある落とし穴まで丁寧に解説し、動くサンプルコードと出力も示します。
C#の変数とは?宣言の基本
変数は値を一時的に保管するための名前付きの領域です。
C#は静的型付け言語であり、各変数には必ず型が紐づきます。
型は格納できるデータの種類と操作の範囲を決め、安全で予測可能なコードを書く助けになります。
- 変数とデータ型の関係(静的型付けのメリット)
静的型付けでは、コンパイル時に型の不整合が検出されます。
たとえば、数値として計算できない文字列を足そうとするミスを早期に発見できます。
最適化や補完(IntelliSense)にも有利で、コードの意図が明確になります。
- 変数名のルールと可読性(キャメルケース推奨)
変数名は英字・数字・アンダースコアを使えますが、数字で始められません。
C#のスタイルガイドでは、ローカル変数やメソッド引数はcamelCase(例: totalCount)を推奨します。
公開プロパティやメソッドはPascalCase(例: TotalCount)にします。
短すぎず長すぎない、意味のある名前を選ぶと可読性が高まります。
参考までに、C#のエイリアスと実体の対応は以下の通りです。
C#の型名 | 実体 (.NET) | 概要 |
---|---|---|
int | System.Int32 | 32ビット符号付き整数 |
double | System.Double | 64ビット倍精度浮動小数点数 |
bool | System.Boolean | 真偽値(true/false) |
string | System.String | 文字列(不変、参照型) |
変数の宣言方法と初期化
型指定の宣言と初期化(int x = 0; など)
型を明示して名前を付け、必要に応じて初期値を与えます。
初期化しないと未割り当てのままとなり、使用前に必ず代入が必要です。
// 明示的な型指定と初期化の例
int count = 0; // 数値(int)
string title = "Hello C#"; // 文字列(string)
double rate = 1.5; // 小数(double)
bool isActive = true; // 真偽(bool)
// 後から代入も可能(ローカル変数は使用前に代入が必須)
int sum;
sum = 10 + 20;
Console.WriteLine($"{count}, {title}, {rate}, {isActive}, {sum}");
0, Hello C#, 1.5, True, 30
補足(リテラル表記)
- 数値の桁区切り: 1_000_000 のようにアンダースコアで可読性を上げられます。
- 浮動小数点の既定はdoubleです。floatを明示するなら 1.23f、decimalは 1.23m と後置します。
varによる型推論の使いどころと注意点
var
は右辺からコンパイラが型を推論します。
推論後の型は静的に固定され、実行時に変化しません。
型が明白なときに可読性を高められますが、曖昧さを生む場合は明示的な型を使いましょう。
// varの型推論例(右辺から決まる)
var n = 42; // int に推論
var message = "Hi"; // string に推論
var pi = 3.14159; // double に推論
// n = "text"; // コンパイルエラー:n は int で固定されている
// var x; // コンパイルエラー:初期化なしの var は不可
Console.WriteLine($"{n.GetType().Name}, {message.GetType().Name}, {pi.GetType().Name}");
Int32, String, Double
使い分けの目安として、公開APIの戻り値やフィールドでは明示的な型、ローカル変数で右辺が明白な場合はvar
が読みやすいことが多いです。
constとreadonlyの使い分け(定数の宣言)
const
はコンパイル時定数、readonly
は実行時に一度だけ設定できるフィールドに使います。
readonly
はコンストラクタで代入でき、以後は変更不可です。
ローカル変数にreadonly
は使えません(C# 8以降のin
やreadonly struct
は別概念)。
using System;
public class Settings
{
// コンパイル時に固定される定数(暗黙的にstatic)
public const double TaxRate = 0.1;
// 実行時に一度だけ設定できる読み取り専用フィールド
public readonly DateTime StartedAt;
public Settings()
{
StartedAt = DateTime.Now; // コンストラクタ内で一度だけ代入可
}
}
var s = new Settings();
Console.WriteLine($"TaxRate={Settings.TaxRate}, StartedAt={s.StartedAt:yyyy-MM-dd HH:mm:ss}");
TaxRate=0.1, StartedAt=2025-08-17 12:34:56
const: 値がアセンブリに埋め込まれるため、外部公開する場合は変更時に依存側の再ビルドが必要。
readonly: 実行時決定の値に適合(現在時刻、設定値の読み込み結果など)。
基本データ型の使い方:int / string / double / bool
intの基本と数値計算のサンプルコード
整数演算(加減乗除、剰余)やインクリメントなどが行えます。
int a = 15;
int b = 4;
int add = a + b;
int sub = a - b;
int mul = a * b;
int div = a / b; // 整数同士の割り算は切り捨て
int mod = a % b; // 剰余
a++; // a = a + 1
b -= 2; // b = b - 2
Console.WriteLine($"add={add}, sub={sub}, mul={mul}, div={div}, mod={mod}, a={a}, b={b}");
add=19, sub=11, mul=60, div=3, mod=3, a=16, b=2
ヒント
- 小数点を含む割り算が必要なら、片方を
double
にキャストします(例:(double)a / b
)。
stringの基本と文字列操作のサンプルコード
文字列は不変(immutable)で、結合や置換は新しい文字列を返します。
補間文字列を使うと読みやすく書けます。
using System;
string first = "C#";
string second = "Programming";
string concat = first + " " + second; // 結合
string interp = $"{first} - {second}!"; // 文字列補間
string upper = concat.ToUpper(); // 大文字化
string replaced = concat.Replace("Programming", "Coding"); // 置換
int len = concat.Length; // 文字数
bool contains = concat.Contains("C#"); // 部分一致
string sub = concat.Substring(0, 2); // 部分文字列
Console.WriteLine(concat);
Console.WriteLine(interp);
Console.WriteLine($"{upper}, len={len}, contains={contains}, sub='{sub}'");
C# Programming
C# - Programming!
C# PROGRAMMING, len=14, contains=True, sub='C#'
ヒント
- 多数回の結合は
StringBuilder
の使用を検討します。 - 空文字は
""
またはstring.Empty
で表現できます。
doubleの基本と小数計算のサンプルコード
double
は倍精度浮動小数点で高速・広範囲ですが、2進表現による丸め誤差が発生します。
double x = 0.1;
double y = 0.2;
double z = x + y;
Console.WriteLine($"0.1 + 0.2 = {z}"); // 期待の0.3と僅かに異なる場合あり
Console.WriteLine($"Equals to 0.3? {z == 0.3}");
// 小数点以下が重要な金額などは decimal を検討
decimal dx = 0.1m;
decimal dy = 0.2m;
decimal dz = dx + dy;
Console.WriteLine($"decimal: 0.1m + 0.2m = {dz}, Equals 0.3m? {dz == 0.3m}");
0.1 + 0.2 = 0.30000000000000004
Equals to 0.3? False
decimal: 0.1m + 0.2m = 0.3, Equals 0.3m? True
boolの基本と条件分岐のサンプルコード
bool
はtrue
かfalse
のみを持ち、条件分岐やループで使います。
bool isMember = true;
int purchase = 1200;
bool canDiscount = isMember && purchase >= 1000;
if (canDiscount)
{
Console.WriteLine("割引が適用されます。");
}
else
{
Console.WriteLine("割引対象ではありません。");
}
// 否定やOR
bool isGuest = !isMember;
bool specialCase = isGuest || purchase > 5000;
Console.WriteLine($"isGuest={isGuest}, specialCase={specialCase}");
割引が適用されます。
isGuest=False, specialCase=False
スコープと有効範囲
ブロックスコープとライフタイム({}内の有効範囲)
ローカル変数は宣言したブロック({}
)内でのみ有効です。
ブロックを抜けると参照できません。
int outer = 10;
{
int inner = 20;
Console.WriteLine($"inner={inner}, outer={outer}"); // OK
}
// Console.WriteLine(inner); // コンパイルエラー:スコープ外
Console.WriteLine($"outer={outer}"); // OK
inner=20, outer=10
outer=10
ライフタイムの目安
- ローカル変数は通常、ブロック終了まで有効。
- 参照型の実体(オブジェクト)はガベージコレクタ管理で、到達不能になった後に回収されます。
シャドーイングを避ける命名と設計
内側のスコープで外側と同名の変数を宣言すると「シャドーイング」が起こり、バグの温床になります。
意図しない上書きを避けるため、内外で別名を用いましょう。
int total = 100;
{
// int total = 50; // シャドーイング(非推奨)
int subtotal = 50; // 別名にして意図を明確に
Console.WriteLine($"subtotal={subtotal}, total={total}");
}
Console.WriteLine($"total={total}");
subtotal=50, total=100
total=100
よくあるつまずきとベストプラクティス
nullとstringの扱い(string.Empty・null許容参照型)
文字列はnull
にもなり得ます。
ヌル参照を防ぐには、初期化やnull合体演算子を活用します。
C# 8以降は「null許容参照型」を有効にすると、コンパイル時に警告で気づけます。
#nullable enable
using System;
string notNull = string.Empty; // 空で初期化
string? mayBeNull = null; // null を許容する宣言(?)
// null合体演算子 ?? と ??=
string name = mayBeNull ?? "デフォルト名";
mayBeNull ??= "初期名"; // null のときだけ代入
// 安全なナビゲーション ?. と null合体 ?? の組み合わせ
int? length = mayBeNull?.Length; // nullならnull、そうでなければ長さ
Console.WriteLine($"name={name}, mayBeNull={mayBeNull}, length={length}");
name=デフォルト名, mayBeNull=初期名, length=2
""
とstring.Empty
は機能的に同じです。プロジェクトのコーディング規約に合わせて統一しましょう。
APIの引数には原則nullを許さず、必要ならstring?
として明示し、ガード(nullチェック)を行います。
数値の範囲外・オーバーフローとchecked
整数演算はデフォルトではオーバーフローが黙って桁あふれ(ラップ)することがあります。
重要な箇所はchecked
で例外を発生させましょう。
using System;
int a = int.MaxValue;
try
{
// 実行時チェック:オーバーフローなら例外
int b = checked(a + 1);
Console.WriteLine($"checked: {b}");
}
catch (OverflowException)
{
Console.WriteLine("checked: Overflow detected");
}
// unchecked 範囲では桁あふれが許容される(ラップする)
int x = int.MaxValue;
int y = unchecked(x + 1); // -2147483648 にラップ
Console.WriteLine($"unchecked: {y}");
checked: Overflow detected
unchecked: -2147483648
コンパイル時定数のオーバーフローは、unchecked
がないとコンパイルエラーになります(例: int c = int.MaxValue + 1;
は不可)。
doubleの誤差とdecimalの検討
金額・個数のように「10進での正確さ」が必要な場合、double
ではなくdecimal
を使います。
decimal
は10進基数で表現され、丸め誤差に強い反面、計算コストは高めです。
物理シミュレーションやグラフィックスではdouble
が一般的です。
bool比較のアンチパターン(== true/falseを避ける)
if (flag == true)
のような比較は冗長です。
シンプルに書きましょう。
bool isReady = true;
// アンチパターン:if (isReady == true)
// 推奨:
if (isReady)
{
Console.WriteLine("準備完了です。");
}
// 否定:if (!isReady)
bool hasError = false;
// アンチパターン:if (hasError == false)
// 推奨:
if (!hasError)
{
Console.WriteLine("エラーはありません。");
}
準備完了です。
エラーはありません。
まとめ
本記事では、C#の変数宣言と基本データ型(int・string・double・bool)を、型指定/初期化、var
の型推論、const
とreadonly
の使い分けから、各型の実用的なコード例まで体系的に解説しました。
ポイントは、静的型付けの強みを活かして型を明確にすること、スコープや命名で可読性を高めること、そしてnull
・オーバーフロー・浮動小数点誤差といった落とし穴を理解して適切に対処することです。
これらの基礎を押さえると、保守性が高く安全なC#コードが書けるようになります。
まずはサンプルを動かし、手を動かしながら自分の言葉で確かめていってください。