C#: 変数とデータ型
変数を「ラベルの貼られた箱」だと考えてみてください。ラベルは名前であり、箱の中にはデータが入っています。箱の適切なサイズと種類を選ぶことで、データを安全かつ効率的に管理することができます。
1. 変数の宣言と初期化
C# は強型付け言語であるため、変数を宣言する際には型を指定する必要があります(あるいは var を使用してコンパイラに型を推論させることもできます):
int age;
age = 25;
string name = "Alice";
double score = 95.5;
また、1行で同じ型の変数を複数宣言することもできます:
int x = 1, y = 2, z = 3;
警告:C# では、初期化されていないローカル変数の使用は許可されていません。コンパイラはエラーを発生させます。
2. 命名規則
C# では、変数名の命名規則が厳格に定められています:
- 文字または
_で始まる必要があります。数字で始まることはできません。 - 文字、数字、および
_のみを含めることができます - 大文字と小文字を区別します(
ageとAgeは異なる変数です) - C#のキーワード(
int、class、returnなど)は使用できません
(1) キャメルケースとパスカルケース
C# には、2つの主要な命名規則があります:
| 識別子の種類 | 形式 | 例 |
|---|---|---|
| ローカル変数、フィールド | camelCase | studentName, totalCount |
| メソッド、クラス、プロパティ | パスカルケース | CalculateSum, Student |
ヒント:camelCase:最初の単語は小文字、それ以降の単語は大文字。PascalCase:すべての単語の大文字。
int studentAge = 18;
double averageScore = 87.5;
string homeAddress = "Beijing";
3. 整数型
C# には、符号付きと符号なしの両方を網羅する 8 種類の整数型が用意されています:
| タイプ | バイト数 | 範囲 | 接尾辞 |
|---|---|---|---|
sbyte |
1 | -128 ~ 127 | — |
byte |
1 | 0 ~ 255 | — |
short |
2 | -32,768 ~ 32,767 | — |
ushort |
2 | 0 ~ 65,535 | — |
int |
4 | -2,147,483,648 ~ 2,147,483,647 | — |
uint |
4 | 0 ~ 4,294,967,295 | U |
long |
8 | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 | L |
ulong |
8 | 0 ~ 18,446,744,073,709,551,615 | UL |
ヒント:Javaとは異なり、C#には符号なし整数型(byte、ushort、uint、ulong)があります。 なお、C#のbyteは符号なし型であり、符号付き版はsbyteであることに注意してください。
▶ サンプル
sbyte sb = -100;
byte b = 200;
short s = -30000;
ushort us = 60000;
int i = 100000;
uint ui = 3000000000U;
long l = 9000000000000000000L;
ulong ul = 18000000000000000000UL;
Console.WriteLine($"sbyte: {sb}");
Console.WriteLine($"byte: {b}");
Console.WriteLine($"short: {s}");
Console.WriteLine($"ushort: {us}");
Console.WriteLine($"int: {i}");
Console.WriteLine($"uint: {ui}");
Console.WriteLine($"long: {l}");
Console.WriteLine($"ulong: {ul}");
sbyte: -100
byte: 200
short: -30000
ushort: 60000
int: 100000
uint: 3000000000
long: 9000000000000000000
ulong: 18000000000000000000
4. 浮動小数点型
| 型 | バイト数 | 精度 | 範囲(概算) | 接尾辞 | 用途 |
|---|---|---|---|---|---|
float |
4 | 7桁 | ±1.5×10⁻⁴⁵ ~ ±3.4×10³⁸ | f |
グラフィックス、ゲーム |
double |
8 | 15~16桁 | ±5.0×10⁻³²⁴ ~ ±1.7×10³⁰⁸ | d (デフォルト) |
科学計算 |
decimal |
16 | 28~29桁 | ±1.0×10⁻²⁸ ~ ±7.9×10²⁸ | m |
金額 |
警告:10進リテラルは、デフォルトで double です。float または decimal に代入する際は、接尾辞を付ける必要があります。そうしないと、コンパイラがエラーを発生させます。
float f = 3.14f;
double d = 3.14;
decimal m = 3.14m;
Console.WriteLine($"float: {f}");
Console.WriteLine($"double: {d}");
Console.WriteLine($"decimal: {m}");
float: 3.14
double: 3.14
decimal: 3.14
ヒント:decimalは金融計算用に設計されており、2進浮動小数点数の誤差を回避します。例えば、0.1 + 0.2は0.3とdoubleとの間では厳密に一致しませんが、decimalとは厳密に一致します。
5. bool 型
bool には true と false の 2 つの値しかなく、1 バイトを占めます。
警告:C言語とは異なり、C#の bool は整数との間で暗黙的な型変換を行うことはできません。if(1) は不正な記述です。if(true) または if(x != 0) と記述する必要があります。
bool isReady = true;
bool isEmpty = false;
Console.WriteLine($"isReady: {isReady}");
Console.WriteLine($"isEmpty: {isEmpty}");
isReady: True
isEmpty: False
6. char 型
C#の char は 2 バイトの Unicode 文字であり、C 言語のような 1 バイトの ASCII 文字ではありません。
char ch1 = 'A';
char ch2 = '\u4e2d';
Console.WriteLine($"ch1: {ch1}");
Console.WriteLine($"ch2: {ch2}");
Console.WriteLine($"ch1 code: {(int)ch1}");
Console.WriteLine($"ch2 code: {(int)ch2}");
ch1: A
ch2: 中
ch1 code: 65
ch2 code: 20013
ヒント:char は一重引用符 'A' を使用していますが、string は二重引用符 "A" を使用しています。これらはまったく異なるタイプです。
7. 文字列型
string は、不変の Unicode 文字シーケンスを表す参照型です。
string greeting = "Hello";
string name = "World";
string message = greeting + ", " + name + "!";
Console.WriteLine(message);
Console.WriteLine($"Length: {message.Length}");
Hello, World!
Length: 13
警告:string は参照型であり、そのデフォルト値は null です(空文字列 "" ではありません)。null 文字列にアクセスすると、NullReferenceException が発生します。
8. var による暗黙の型指定
C# 3.0 では var キーワードが導入され、これによりコンパイラは初期値から型を推論できるようになりました:
var count = 42;
var price = 9.99m;
var label = "hello";
var flag = true;
Console.WriteLine(count.GetType().Name);
Console.WriteLine(price.GetType().Name);
Console.WriteLine(label.GetType().Name);
Console.WriteLine(flag.GetType().Name);
Int32
Decimal
String
Boolean
警告:var は「任意の型」を意味するものではありません。変数の型はコンパイル時に決定され、初期化する必要があります。以下の記述は不正です:
var x;
var x = null;
ヒント:型名が長い場合や、文脈から型が明らかな場合は、var を使用してください。ただし、読みやすさが損なわれる可能性があるため、過度な使用は避けてください。
9. sizeof — 型のサイズを確認する
sizeof は、型が占めるバイト数を返します。プリミティブ型に対しては直接使用できますが、その他の型に対しては unsafe コンテキストが必要です。
▶ サンプル
Console.WriteLine($"sbyte: {sizeof(sbyte)} bytes");
Console.WriteLine($"byte: {sizeof(byte)} bytes");
Console.WriteLine($"short: {sizeof(short)} bytes");
Console.WriteLine($"ushort: {sizeof(ushort)} bytes");
Console.WriteLine($"int: {sizeof(int)} bytes");
Console.WriteLine($"uint: {sizeof(uint)} bytes");
Console.WriteLine($"long: {sizeof(long)} bytes");
Console.WriteLine($"ulong: {sizeof(ulong)} bytes");
Console.WriteLine($"float: {sizeof(float)} bytes");
Console.WriteLine($"double: {sizeof(double)} bytes");
Console.WriteLine($"decimal: {sizeof(decimal)} bytes");
Console.WriteLine($"char: {sizeof(char)} bytes");
Console.WriteLine($"bool: {sizeof(bool)} bytes");
sbyte: 1 bytes
byte: 1 bytes
short: 2 bytes
ushort: 2 bytes
int: 4 bytes
uint: 4 bytes
long: 8 bytes
ulong: 8 bytes
float: 4 bytes
double: 8 bytes
decimal: 16 bytes
char: 2 bytes
bool: 1 bytes
10. const 定数
値を変更できないコンパイル時定数を宣言するには、const を使用します。これらは宣言時に初期化する必要があります:
const double Pi = 3.14159265358979;
const int MaxRetry = 3;
const string AppName = "MyApp";
Console.WriteLine($"Pi = {Pi}");
Console.WriteLine($"MaxRetry = {MaxRetry}");
Console.WriteLine($"AppName = {AppName}");
Pi = 3.14159265358979
MaxRetry = 3
AppName = MyApp
警告:const の名前は通常、PascalCase 表記を使用します。この値はコンパイル時に決定可能でなければならず、変数やメソッド呼び出しの結果であってはなりません。
ヒント:実行時に決定される「定数」が必要な場合は、代わりに readonly フィールドを使用してください。
11. 型のデフォルト値
初期値が指定されていない場合、各型にはデフォルト値が設定されています:
| タイプ | デフォルト値 |
|---|---|
sbyte / byte / short / ushort / int / uint / long / ulong |
0 |
float |
0.0f |
double |
0.0d |
decimal |
0.0m |
char |
'\0' |
bool |
false |
string |
null |
| 任意の参照型 | null |
▶ サンプル
int defaultInt = default;
bool defaultBool = default;
char defaultChar = default;
string defaultString = default;
double defaultDouble = default;
Console.WriteLine($"int: [{defaultInt}]");
Console.WriteLine($"bool: [{defaultBool}]");
Console.WriteLine($"char: [{(int)defaultChar}]");
Console.WriteLine($"string: [{defaultString}]");
Console.WriteLine($"double: [{defaultDouble}]");
int: [0]
bool: [False]
char: [0]
string: []
double: [0]
ヒント:default キーワードを使用すると、あらゆる型のデフォルト値を取得できます。これはジェネリック型で特に頻繁に使用されます:default(T)。
12. 値型と参照型 — はじめに
C#の型は、大きく分けて2つのカテゴリに分類されます:
| カテゴリ | ストレージ | 割り当ての挙動 | 代表的なタイプ |
|---|---|---|---|
| 値型 | スタック(通常) | 値をコピーする | int, bool, char, decimal, struct, enum |
| 参照型 | ヒープ | 参照先(アドレス)をコピー | string, class, object, 配列 |
int a = 10;
int b = a;
b = 20;
Console.WriteLine($"a = {a}, b = {b}");
string s1 = "hello";
string s2 = s1;
s2 = "world";
Console.WriteLine($"s1 = {s1}, s2 = {s2}");
a = 10, b = 20
s1 = hello, s2 = world
警告:s1 は "world" にはなりませんでした。これは、string が不変であるためです。つまり、s2 = "world" は元のオブジェクトを変更せず、s2 が新しいオブジェクトを指すようにするだけです。 値型の代入では実際の値がコピーされますが、参照型の代入では参照がコピーされます。しかし、stringは不変であるため、値型のように振る舞います。
❓ よくある質問
var と dynamic の違いは何ですか?var はコンパイル時に型を決定し、型安全です。 dynamicは実行時に型を解決し、コンパイル時の型チェックがなく、パフォーマンスが劣り、エラーが発生しやすいです。decimal が double より優れているのですか?decimal は10進数形式で格納されるため、0.1 を正確に表現できます。 doubleは2進数形式で保存されるため、0.1を正確に表現できず、累積的な丸め誤差が生じます。string は値型ですか、それとも参照型ですか?string は参照型ですが、不変であるため、代入の際は値セマンティクスが適用されます。つまり、ある変数を変更しても、別の変数には影響しません。const と readonly の違いは何ですか?const は、宣言時に代入する必要があり、暗黙的に static であるコンパイル時定数です。 readonlyは、コンストラクタ内で代入可能であり、インスタンスごとに異なる可能性がある実行時定数です。📖 まとめ
- C# は強型付け言語であり、変数には型を宣言するか、
varを使用して型推論を行う必要があります - ローカル変数にはキャメルケースを使用し、メソッドやクラスにはパスカルケースを使用します
- 整数型は8種類あります(符号なし型を含む)。その中で、
intが最もよく使われています。 - 資金用途には
decimal、科学計算用途にはdouble、グラフィックス用途にはfloatを使用してください boolは整数との間で暗黙的な型変換を行うことはできません。また、charは 2 バイトの Unicode 型です。varは初期化が必要であり、型はコンパイル時に決定されますconstはコンパイル時定数(PascalCase)を定義し、readonlyは実行時定数を定義しますdefaultキーワードは、あらゆる型のデフォルト値を取得します- 値型の代入では値がコピーされ、参照型の代入では参照がコピーされる
📝 練習問題
int変数ageに自分の年齢を、string変数nameに自分の名前をそれぞれ設定し、両方を表示するfloat、double、decimalをそれぞれ用いて0.1 + 0.2を計算し、その結果が0.3と完全に一致するかどうかを比較するsizeofを使用して、int、double、char、およびboolのバイトサイズを出力するconst double Pi = 3.14159265を宣言し、半径 5 の円の面積を計算して、その結果を出力してくださいdefaultキーワードを使用して、int、bool、char、およびstringのデフォルト値を取得し、出力する