~情報を再利用する、クラスのフィールドを構成する~

1. 変数とは?

この記事では、当社の新人エンジニア研修の参考にC#を解説します。

前回は「C#を初めて学ぶ新人社員の皆さんへ」ということでC#の特長やオブジェクト指向の概要をお話しました。

今回からは、いよいよC#の基本文法について学んでいきます。まずは、変数データ型について解説しましょう。

この章のサンプルコードを実行するプロジェクトを作ります。以下の図をご覧ください。ソリューションの上で右クリック→追加→新しいプロジェクトと進んでクリックします。

新人エンジニア

前回と同じように、コンソールアプリを選び、プロジェクト名は Chap02 としてプロジェクトを作成してください。Program.csが自動作成されて、コードが表示されますが、もし表示される位置がプロジェクトエクスプローラーと重なっていたり、使いにくい部分があれば、講師に聞いてください。下図のような状態になれば、準備完了です。

新人エンジニア

変数とは、アプリケーションの二大要素である情報(データ)を入れる箱のことです。各々のデータには名前(ニックネーム)を付けることができるようになっており、それを変数と呼びます。変数を使うことで、データの再利用や演算が容易になります。

プログラミングに限らず、「名前」という仕組みがないと非常に不便ですよね。現実でも、「クリスマスイブの日に橋の下に捨てられていた白い犬」を毎回その長い呼び名で呼ぶのではなく、「三太」と名前をつければ簡単に指し示すことができます。これが変数の役割とよく似ています。

設計において、適切な名前をつけられるかどうかは非常に重要な要素
(Ruby開発者:まつもとゆきひろ 〜「プログラマが知るべき97のこと」より)

コンピュータの本質は「計算機」です。計算機はデータを処理するため、一時的にデータを保管する場所が必要です。その場所に「名前」を付けて扱いやすくしたものが変数です。

例えば、メインメモリ上のアドレスをそのまま使うのは人間には分かりにくいです。そこで、「わかりやすい名前(変数名)」を付けてあげることで、プログラム中で扱いやすくしています。

変数を「引っ越しの荷物を入れるダンボール箱」になぞらえることがあります。
ダンボール箱にラベルがないと、中身が何か分からず困ります。同様に、変数にも「何を入れるか」の名前付けが重要なのです。

新人エンジニア
変数のイメージは箱

また、箱ごとに「食器用」「電化製品用」のように用途を決めておけば混乱しません。同様に、数値や文字列など、変数にどんなタイプのデータを入れるかをあらかじめ決めるのがデータ型です。データ型を決めることで、間違ったデータ操作を防ぎます。

  • 例:
    • 2 + 35 という数値演算
    • "Hello " + "World""Hello World" という文字列結合
    • 数値同士であれば加減乗除が可能ですが、文字列同士の演算では加算が連結という意味になる

C#でも他の言語と同様に、整数値や文字列、真偽値など様々な型を扱います。また、前章で出てきたクラスやオブジェクトを変数に入れることも可能で、これはプログラマーが作るデータ型と言えます。データ型を理解することは、C#を使いこなすうえで欠かせません。

変数は英語で(Variable)と書きます。「変わるもの」という意味です。プログラム処理によって値が刻々と変化する可能性があるからです。それに対して、変化しない(変えられない)ものを「定数(Constant)」と呼びます。いずれもC#の基本を学ぶ上で欠かせない知識です。ここではまず変数を、続いて定数を学んで行きましょう。

2. 変数の基本

以下のサンプルプログラムでは、型の異なる4つの変数を宣言し、それぞれの値をコンソールに出力します。このプログラムを実行するために、Chap2のプロジェクトにクラスを一つ追加しましょう。クラスを追加するショートカットは、ctrl + shift + a です。

namespace Chap02;
using System;

public class Example01 {
    public static void run() {
    int data1 = 1;
    double data2 = 1.0;
    bool flag = false;
    char c = 'A';

    Console.WriteLine(data1);
    Console.WriteLine(data2);
    Console.WriteLine(flag);
    Console.WriteLine(c);
    Console.WriteLine("data1");
    }
}

次に、Program.csのトップレベルステートメントを以下のように変更しましょう。

// See https://aka.ms/new-console-template for more information
// Console.WriteLine("Hello, World!");
using Chap02;

Example01.run();

次に、実行するプロジェクトをChap02に変更します。Visual Studioの実行ボタン(右側)のプルダウンメニューから、スタートアッププロジェクトの構成を選んでください。

新人エンジニア

出てきた画面で、シングルスタートアップのプロジェクトをChap02に変更しましょう。

新人エンジニア

準備が出来たら実行ボタンを押してください。今後、新しい章に移って最初のサンプルコードを実行する際には、同様な設定が必要になりますので、覚えておいてくださいね。

<結果>

1
1.0
False
A
data1

C#に限らず、一般にプログラムは「上から下へ」順次実行されます。
  1. 変数を 宣言 する:int data3;
  2. 値を 代入 する:data3 = 10;
  3. 宣言と代入を一行で書く:int data3 = 10;
  4. 変数を使う(参照 する):Console.WriteLine(data3);

ここで注意すべきは、最後のConsole.WriteLine("data1") のように、変数名を""で囲ってしまうと、意図しない結果になるということです。””で囲った記述は文字列リテラルというデータになり、画面出力が"data1" という文字列そのものになります。

また、変数には他の変数の値を代入することもできます。

int data4 = data3;

そして、演算の結果を代入することもできます。

data4 = data3 + 1;

変数に新しい値を代入すると、もともと入っていた値は上書きされ、前の値は捨てられます。

data3 = data3 + 1;

例題

例題

実行結果はどうなるでしょう? その理由は?

int a = 1;
int b = a;
a = 2;
Console.WriteLine(a + ":" + b);

変数の有効範囲(ローカル変数、クラスのフィールド、グローバル変数)

ローカル変数:変数には、有効範囲があります。今回紹介したのはローカル変数と呼ばれるタイプのものです。mainメソッドの最初と終わりにある{ }で囲まれた範囲をブロックと呼ぶのですが、ローカル変数とはブロックの範囲内だけで有効な変数です。処理がブロックを出た時点でローカル変数は破棄されてしまい、使えなくなります。

フィールド:次に、第一章でご紹介したクラスのフィールドも変数です。これは、クラスのブロックの中、メソッドの外に宣言する変数です。以下の例をご覧下さい。

public class SampleClass {
    int data1 = 0; // クラスブロックの中で、且つメソッドの外で宣言された変数は、フィールドになる

    static void sampleMethod() {
      // 何かの処理
    }
}

フィールドは、そのクラス全体で有効な変数です。クラス内部のどのメソッドでも利用可能なj情報となります。

グローバル変数:最後に、アプリケーション全体で共通して使える変数をグローバル変数と呼ぶのですが、C#にはグローバル変数という概念がありません。よって、C#の変数は全て何らかの有効範囲を持つことになります。この有効範囲のことを、変数のスコープと呼びます
また、C#では値が未設定の変数をそのまま使おうとするとコンパイルエラーになります。

int data1; // 変数を宣言しただけで値が入っていない
Console.WriteLine(data1); // ← ここで使おうとするとエラー

変数宣言と同時に初期の値を設定することを、変数の初期化と言います。「変数は初期化してから使う」のが原則です。

直接記述される値のことを「リテラル」と呼びます。例えば "Hello", 1, 1.0, false, 'C' , は全てリテラルです。

3. 変数の宣言

C#では、変数を宣言するときに「型」を先に書きます。これは静的型付け言語の特徴です。

型名 変数名;


  • C#での「名前(変数・メソッド・クラスなど)」を識別子と呼びます。
  • 識別子には、英字と数字、アンダースコア _ などが使えますが、先頭を数字にしてはいけない、という規則があります。

たとえば、int 1stNumber; のような宣言はできません。また、C#にも予約語があり、変数名に予約語は使えません。

int int = 0; // これはエラー

このような宣言ができてしまうと、int が型なのか変数なのか区別できないからです。変数名に使えないものを、次章でもう少し詳しく見ていきましょう。

予約語とリテラル

C#にもたくさんの予約語public, class, if, static...)や決まった値を表現するために予約語となっているリテラル(true, false, null...)があります。これらは変数名として使うことはできません。細かい話をすると、一般に予約語と言われているものも、広義では全てリテラルに分類されます。Visual Studioでは予約語がコードの編集画面で色分けされるので、変数名に使えないリテラルを一目で判断できます。

実験:同じ変数名を2回宣言してみる

int data1 = 10;
int data1 = 20; // 再度宣言するとどうなるか?

→ 「変数が重複している」エラーが出るはずです。同一有効範囲に同じ変数名が複数あると区別がつかないからですね。

実験:変数の参照と宣言の順番を逆にしてみる

Console.WriteLine(data1);
int data1 = 10;

→ 変数が見つからない旨のエラーが出るでしょう。前述のように処理は上から下へ実行されて行きますから、まだ宣言されてもいない変数を使うことはできないのです。

静的型付けと動的型付け言語

C#は変数の宣言時に変数の型を明示します。これを静的型付けといいます。一方、動的型付けといって宣言時に変数の型を明示しない言語もたくさん存在します。

静的型付けの言語の代表例は、C#を始めJava、C++、などがあります。

一方動的型付けの言語の代表例は、Python、JavaScript、Ruby、PHPなどです。

どちらも一長一短がありますが、宣言時にデータ型を指定しない動的型付け言語では、勘違いで本来の型を間違えた使い方をしてもエラーにならず、予期しない動作を引き起こす場合があります。なので、最初に学ぶ言語としては、コンパイル時に型エラーを検出しやすい静的型付け言語の方が勉強しやすい、という考え方もあります。

4. C#で使用できる主な組み込み型

C#では下記の組み込み型があります。組み込み型とは、言語があらかじめ持っているデータ型のことです。

ビット幅値の範囲・内容
booltrue または false
byte8ビット符号なし(※) / 符号あり sbyte が別にある
char16ビットUnicode 文字 (U+0000 ~ U+FFFF)
short16ビット-32768 ~ 32767
int32ビット-2,147,483,648 ~ 2,147,483,647
long64ビット-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
float32ビット単精度浮動小数点数(-3.4×10^38~3.4×10^38 など)
double64ビット倍精度浮動小数点数(±5×10^-324~±1.7×10^308 など)
decimal128ビット高精度(財務計算などで使用)

メモリ上の表現

  1. int の 1 はメモリ上で「32ビットの2進数」で表される
  2. double の 1.0 は浮動小数点数と呼ばれるint形とは別の形式の2進数表現になる

「同じ 1 でも、整数の1と実数の1.0 はメモリ上のビットパターンが異なる」ということが「型変換(キャスト)」で重要になってきます。

5. なぜ、変数を使うのか?

変数を使う理由を一言で表すと、「データにその意味が分かる名前を付けて、使い回し、変更ができる」からです。

以下のExample06は、あなたが現在22歳だとして、将来の年齢をコンソールに表示するプログラムです。前回と同じように、Chap02プロジェクトにExample02というクラスを作成してください。

namespace Chap02;
using System;

public class Example02 {
    public static void run() {
        int yourAge = 22;

        Console.WriteLine("あなたは今" + yourAge + "才です");
        Console.WriteLine("あなたは10年後" + (yourAge + 10) + "才です");
        Console.WriteLine("あなたは20年後" + (yourAge + 20) + "才です");
        Console.WriteLine("あなたは30年後" + (yourAge + 30) + "才です");
        Console.WriteLine("あなたは40年後" + (yourAge + 40) + "才です");
        Console.WriteLine("あなたは50年後" + (yourAge + 50) + "才です");
    }
}

前回と同じように、Example02のコードを実行できるよう、トップレベルステートメントを編集しましょう。

// See https://aka.ms/new-console-template for more information
// Console.WriteLine("Hello, World!");
using Chap02;

//Example01.run();
Example02.run();

<結果>

あなたは今22才です
あなたは10年後32才です
あなたは20年後42才です
あなたは30年後52才です
あなたは40年後62才です
あなたは50年後72才です
  1. yourAge という「あなたの年齢」だと分かりやすい名前が付いています。数値 22 のままでは何を表す数字か不明ですが、yourAge と名前を付けてやることで、データの意味を明確にしているのです。
  2. 年齢が1歳増えた場合は、単に yourAge = 23 と書き換えれば良いですね。

このように、変数を使うことでデータの意味付け、使い回し、変更が容易になります。

新人エンジニア
キャメルケース

変数名は キャメルケース (camelCase) で付けるのが一般出来です。キャメルケースとは、単語をつなげるときに、最初の文字だけを大文字にするやりかたです。例: yourAge, myFirstName など
C#のローカル変数では小文字始まりが一般的です(ただし意見は分かれる場合あり)。

6. 定数を使うとき

前述の様に、変数とは処理で値を変えながら使うものです。それに対して「変更できない」値を持つものを定数と言います。例えば成人年齢は法令で決められており、後から変更する必要もありませんし、逆に変更できてしまっては意味を成さない値です。定数の宣言はC#ではconstキーワードを使います。英語の【constant(常に一定で変わらないもの)】の省略形です。

以下のExample03クラスをChap02プロジェクトに追加し、トップレベルステートメントを変更して実行してみてください。

namespace Chap02;
using System;

public class Example03 {
    public static void run() {
        const int ADULT_AGE = 18;
        // ADULT_AGE = 20;  // ← このコメントを外すとコンパイルエラー:定数の値は変更できない

        Console.WriteLine("成人年齢は" + ADULT_AGE + "才です");
        Console.WriteLine("今年の成人は10年後" + (ADULT_AGE + 10) + "才です");
        Console.WriteLine("今年の成人は20年後" + (ADULT_AGE + 20) + "才です");
        Console.WriteLine("今年の成人は30年後" + (ADULT_AGE + 30) + "才です");
        Console.WriteLine("今年の成人は40年後" + (ADULT_AGE + 40) + "才です");
        Console.WriteLine("今年の成人は50年後" + (ADULT_AGE + 50) + "才です");
    }
}

<結果>

成人年齢は18才です
今年の成人は10年後28才です
今年の成人は20年後38才です
今年の成人は30年後48才です
今年の成人は40年後58才です
今年の成人は50年後68才です

新人エンジニア
スネークケース

定数は全大文字+アンダースコアというスネークケースがよく使われます。スネークケースとは、単語をつなげるときにアンダースコアを間に挟む、というやり方です。出来上がった文字列の見た目が蛇に似ていることから、この呼び方になりました。

7. char型は整数のように扱える?

次のExample04を見てください。

namespace Chap02;
using System;

public class Example04 {
    public static void run() {
        char a = 'A';
        a += (char)32;
        Console.WriteLine(a);
    }
}

<結果>

a

C#のchar型は内部的には「文字コード(16ビットの数値)」として扱われます。 つまり、上の表にある16ビットの整数shortと同じ形式なのです。'A' のコードに 32 を足すと 'a' になるわけです。(ASCIIテーブルなどを参照)
文字の大小変換や暗号化などで、charを数値的に操作するテクニックが使われる場合があります。

変数と定数についての解説は、とりあえずは以上になります。サンプルコードも増えてきましたので、この章の最後に、C#でクラスの住み分けを行うための仕組みである名前空間(namespace)について、もう少し掘り下げて解説しておきましょう。

8. クラスはnamespaceを使って整理する

C#では名前空間「namespace」を使ってクラスを整理します。パッと見ではなんのことだか分かりにくい用語ですが、要するに名前空間とはクラスの住所を表すものです。このクラスはどこそこにあるクラスですよ、という宣言なのです。

オブジェクト指向のアプリケーションは、クラスの集合体である、という話は前章で解説しました。一つのアプリケーションにはたくさんのクラスが含まれています。全てのクラスを一か所においてしまっては、たくさんありすぎて、どれがどれだか分かりづらくなりますよね。そこで、機能別に名前空間を作り、クラスを分類して構成を分かりやすくしよう、というわけです。

先ほどのExample04クラスを再掲しますので、namespaceの記述にご注目ください。

namespace Chap02;
using System;

public class Example04 {
    public static void run() {
        char a = 'A';
        a += (char)32;
        Console.WriteLine(a);
    }
}

このように記述することで「Chap02」という名前空間の下にExample04クラスが所属することになります。名前空間は、大文字から始まるキャメルケースで作るのが一般的です。

当然のことですが、同一名前空間内に同名のクラスを作ることはできません。使いたいクラスを指定する際、どのクラスか判別できなくなるからです。逆に、名前空間が違えば、同名のクラスをいくつでも作ることは可能です。外部のクラスを使うときには、using クラス名 という宣言を行いますが、その時に名前空間を指定することで、同じクラス名でもどこのクラスかを特定できます。名前空間には同じソリューション(プロジェクト)内でクラス名の衝突を防ぐ効果もあるわけです。

9. 別のnamespaceにあるクラスを呼び出して使用する

別のnamespaceにあるクラスを呼び出して使用してみましょう。以下のプログラムでは、C#の日時クラス System.DateTimeを“フルネーム”で使用しています。この場合のフルネームとは、名前空間を含めたクラス名を使う、という意味です。これを、完全修飾名と言います。

namespace Chap02;
using System;

public class Example05 {
    public static void run() {
        // 完全修飾名で呼び出し
        Console.WriteLine(System.DateTime.Now);
    }
}

<結果>

2025/02/18 16:45:55

(表示形式はPCのロケールや設定によります)

さらに、using System; と書いておけば、単に DateTime.Now と書けます。usingで、Systemという名前空間を使いますよと宣言してありますから、その配下にあるクラスは、クラス名だけを指定すれば使えるようになります。これが、名前空間の利用法です。プロジェクトの規模が大きくなればなるほど、当然ですがクラス数も多くなります。クラスを名前空間で分け、更に一つの名前空間を木構造にして多数のクラスを目的別に分類してわかりやすく整理することで、メンテナンスしやすいアプリケーションを構築することが出来ます。

namespace Chap02;
using System;

namespace Chap02 {
    public class Example05 {
        public static void run() {
            Console.WriteLine(DateTime.Now); // System.を取っても正常に動作する
        }
    }
}

ただし誤解しがちですが、using は「クラスを読み込む」わけではなく「外部のクラスを使う場合に、いちいちフルネームで名前空間を書くことを省略できる」ようにする仕組みです。C#は外部のクラス名が処理に書かれていれば、そのクラスを探しに行きます。usingで名前空間が指定されていれば、そこにあるクラスを検索して使えるようにしてくれる、というわけです。

using System;
using System.Text;
// など

と書いておけば、その名前空間配下のクラスを完全修飾名なしで呼び出せるようになるのですね。

using System.Text;StringBuilder クラスを StringBuilder sb = new StringBuilder(); のようにシンプルに書ける

<まとめ:隣の人に正しく説明できたらチェックを付けましょう>

□ 文字型はシングルクォーテーション ’ で囲い、文字列はダブルクォーテーション " で囲うのは変数名と区別するためである

□ 変数を作成することを「変数の宣言」といい、変数に値を入れることを「代入」、変数に入っている値を見ることを「参照」という

□ 変数には、他の変数の値を代入することができ、また演算の結果を代入することもできる

□ C#にはスコープが限定されたローカル変数しかなく、グローバル変数は存在しない

□ 変数は初期化してから使うのが基本

□ 変数の宣言では、変数に入れる値の型をはじめに指定する必要があり、それを静的型付けという

□ まず最初に真偽値のbool、整数値のint、浮動小数点数のdoubleの3つの型は最低限覚える

□ namespaceの目的は①わかりやすい分類整理②名前空間の提供③クラス名の衝突を避ける、の3つ

まとめができたら、実際にコードを書いてみて、自分で試行錯誤しながら習得を進めましょう。


変数とデータ型はあらゆるプログラミング言語の基礎です。ここでしっかり理解しておくと、後のオブジェクト指向や高度なライブラリ操作を学ぶときに大いに役立ちます。

次回は、「3章. 演算子でプログラムに計算させる」を学びます。









最後までお読みいただきありがとうございます。