C#で使える定数
C#では定数を宣言する際にconst
またはreadonly
を使います
それぞれの特徴は下記の通りです
定数 | 値決定タイミング | パフォーマンス |
---|---|---|
const | コンパイル時 | 優れている |
readonly | 実行時 | やや劣る |
"値の変わらないもの"という役割は同じですが、それぞれ大きく異なる動きをするため、用法を誤るとバグに繋がってしまうかも!?
どっちを使うべきか?
タイトルでネタバレしちゃってますが、基本的にはreadonly
を使うことが推奨されています
以下の観点でなぜresdonly
を使うべきなのか考察していきます
- 値変更後の再コンパイル必要有無
- 扱える型の違い
値変更後の再コンパイル必要有無
const
とreadonly
の最も大きな違いは値決定のタイミングです
const
はコンパイル時、readonly
は実行時に値が決まります
C#コードはビルド時にコンパイルが行われ、コンパイル完了後の成果物を使用して処理が実行されます
つまり、定数の中身に変更があった場合、コンパイル時に値が決定するconst
は、再ビルドを実行しないと定数値の変更が処理に反映されません
例) アセンブリの変更時に再ビルト実行が漏れたケース
VersionInfo
というアセンブリのクラスVersionDefinition
に以下の定数が設定されているとします
class VersionDefinition
{
public static readonly double AvailableVersion = 1.5;
public const double CurrentVersion = 2.0;
}
この定数を別アセンブリから参照する以下の処理があったとします
if (VersionDefinition.CurrentVersion > VersionDefinition.AvailableVersion)
{
Console.WriteLine($"This version is available!");
}
現状、定数の変更がなければ問題なくConsole.WriteLine()
が実行されます
ただ、アセンブリVersionInfo
のアップデートが行われ、以下のように変更があった場合を考えてみましょう
class VersionDefinition
{
public static readonly double AvailableVersion = 2.0;
public const double CurrentVersion = 2.1;
}
このケースでVersionInfo
の再ビルドが漏れると実行時の各定数の値は以下になります
AvailableVersion
: 2.0
CurrentVersion
: 2.0
if
の条件式がfalse
になりアセンブリVersionInfo
で設定した定数が意図する処理とは異なる挙動になってしまいますね
長期的なメンテナンス性を加味するとreadonly
を使うのが得策と言えるでしょう
扱える型の違い
const
はコンパイル時に値が決まっていなければならないという特性上、扱える型に制限があります
具体的には、
- 整数型や浮動小数型
- 列挙型
- 文字列型
のみとなります
それに対して、readonly
は処理実行時に値を決定するため、すべての型に対応可能です
この問題に関しては実装時に気づくことができるため不具合につながる可能性等は低いですが、const
で対応できない定数はreadonly
で補えることを知っておくと便利でしょう
じゃあconstはいつ使うの?
上記の理由から定数は基本的にreadonly
を使用することを推奨しますが、const
を使うメリットはあります
それはパフォーマンスです
実行時に値へアクセスするreadonly
よりも、コンパイル時に値が決まっているconst
の方が処理時間が早いのは自明ですね
将来的に値の変更が想定されない定数や、参照されているアセンブリごとに値変更の反映タイミングをずらしたい定数などはconst
が有効となります
参考
Effective C# 6.0/7.0 Bill Wagner (著), 鈴木 幸敏 (監修, 翻訳)