定数

変化しない「値」

プログラミングで頻繁に利用される変数は、必要に応じて値を変化させることができる「データの入れ物」です。
これに対して定数という「値が変化しない入れ物」も存在します。

const


static void Main(string[] args)
{
    //定数
    const double PI = 3.14159265;

    double radius = 10;

    Console.WriteLine("半径{0}の円の面積は: {1}",
        radius, radius * radius * PI);

    Console.ReadLine();

    //以下のように定数を書き換えようとするとエラーになる
	//PI = 0;
}
半径10の円の面積は: 314.159265

4行目のconstというキーワードと共に宣言されているのが定数です。

const定数は一見普通の変数と変わりありませんが、以下のようなルールがあります。

  1. 定数の宣言と同時に初期化しなければならない
  2. 定数には値を代入することはできない
  3. コンパイル時に、コード中で使用した定数は指定した値に置き換えられる

定数はその名の通り、値が変化しない入れ物です。
そのため、別の値を代入しようとするとエラーになります。
代入処理ができないため、宣言と同時に初期化が必要となります。

上記のルール3の意味は、コードをコンパイルする時に、コード中に記述されている定数を実際の値(リテラル)に置き換えるという意味です。


static void Main(string[] args)
{
    //定数
    const double A = 3;
    const double B = 5;
    const double C = 9;

    Console.WriteLine("{0} × {1} × {2} = {3}", A, B, C, A * B * C);

    Console.ReadLine();
}

//上のコードはコンパイル時に以下のコードに置き換えられる

static void Main(string[] args)
{
    Console.WriteLine("{0} × {1} × {2} = {3}", 3, 5, 9, 3 * 5 * 9);

    Console.ReadLine();
}

定数A、B、Cを使用すると、そこに実際の値を直接記述したのと同じ扱いになります。
コンパイル時に書き換えられるということは、プログラムの実行前に値が確定するということです。
(通常の変数はプログラムを実行する毎に必要に応じて代入の処理が入る)
このことは変数を使用するよりも速度面で有利になります。

なお、定数も変数と同じように名前は自由に付けられますが、変数と見分けが付くようにするのが一般的です。
例えば上記コードではすべて大文字で記述することで変数と区別しています。
このほか、定数であることを表す接頭語(プレフィックス)として「c_」を付ける、などがよく用いられます。
(c_pi、とするなど)

「コードを置き換える」機能であることを理解して使用しないとトラブルが発生する場合もあります。
それは、他のプログラムから使用される値をconst定数にする場合です。

Aというプログラムで定義されているconst定数をBというプログラムからも使用しているとします。
プログラムAをバージョンアップした際にconst定数の値を更新すると、プログラムBとの値に食い違いが発生します。
プログラムBのコンパイル時にプログラムAから読み取ったconst値をそのまま保存しているからです。
プログラムAでconst定数を変更した場合はプログラムBをコンパイルし直す必要があります。
(「constのバージョニング問題」という)

最初のうちはそのようなプログラムを作ることはないでしょうから問題にはなりませんが、そういう問題もあるということは覚えておいてもいいかもしれません。

メンバーにする場合はstaticを付けない

const定数はメンバー変数(メンバー定数)としても使用できますが、その場合は「static」を付けて使用することはできません。
これは、const定数は上記のように「コードを置き換える」機能であるためですが、そもそもstaticとは何かをまだ説明していないので、今は「そういうものだ」という認識で構いません。
(Visual Studioならばコード記述の段階でエラー表示されるのですぐに気付くと思います)
詳しくはクラスの機能の説明の際に改めて説明します。


class Program
{
    //メンバー定数
    //「static」は付けないこと
    const double PI = 3.14159265;

    static void Main(string[] args)
    {
        Console.WriteLine(PI);

        Console.ReadLine();
    }
}

readonly

C#ではもうひとつreadonlyというキーワードで定数を作ることができます。
正しくは名前の通り「読み取り専用(read only)」で定数ではないのですが、似たような機能が実現できます。


class Program
{
    static readonly double PI = 3.14159265;

    static void Main(string[] args)
    {
        Console.WriteLine(PI);

        Console.ReadLine();
    }
}

const定数の時とは違い、Mainメソッド(staticメソッド)から使用する場合は「static」が必要です。
const定数はローカル変数にもメンバー変数にもできますが、readonlyはメンバー変数としてのみ使用できます。

readonlyは「読み取り専用の変数」です。
値が変更できないので実質的に定数ですが、const定数のようにコンパイル時にコードを置き換えるようなことはせず、単純に値が変更不可能な入れ物となります。

readonly変数は宣言時に初期化するほか、クラスのコンストラクター内でも初期化ができます。
(以下はstatic変数なので静的コンストラクター内で初期化している)


class Program
{
    static readonly double PI;

    static Program()
    {
        PI = 3.14159265;
    }

    static void Main(string[] args)
    {
    }
}

このあたりのこともクラスの機能の説明の際に改めて説明します。