PG日誌

読者です 読者をやめる 読者になる 読者になる

PG日誌

主にc#の事を書いています

c#のconstとstatic readonlyの使い分け

c#

f:id:Takachan:20170114224940j:plain

c#でプログラム書いてるとコードを書いているときは、constとreadonlyの区別ってあんまりありませんよね。

ついつい定数は全部、constと書いてしまいます。

public static class HogeDefine
{
    public const uint MaxLength = 10;
    
    public static uint DataSize = 64;
}

...

public void Main(string[] args)
{
    // constのほう
    for(int i = 0; i < HogeDefine.MaxLength; i++)
    {
        // 中略
    }
    
    // readonlyのほう
    byte bArray = new byte[HogeDefine.DataSize];
}

だいたい、両方とも使い勝手は全く同じです。

が、これ、コンパイルした後に明確に違いが現れます。

コンパイル後は、以下のように変化してしまいます。

public void Main(string[] args)
{
    // constのほうは、リテラルに置き換わってしまう
    for(int i = 0; i < 10; i++)
    {
        // 中略
    }
    
    // readonlyのほうは定義先の参照のまま
    byte bArray = new byte[HogeDefine.DataSize];
}

「constの方がリテラルの置き換わって」しまうのですね。

何が言いたいかというと

1) DLLが複数あって
2) constが定義されているDLL外から参照される可能性があり
3) 各々のDLLのライフサイクルが違う

a) constの値が変更される
b) リンク先がコンパイルされる

タイミングが違って宣言元のDLLをリリースしてしまうと、

「参照先のDLLで古いconstの値が使用されっぱなし」

な状態になって思わぬ不具合が発生する場合があります。

この不具合の連絡が来ると

「10」が設計値なのに「12」になってる!!

どうして!?(コンパイラのバグ・・・?)

みたいな、わかる人にはわかるけど保守担当は事情を知らないので割と頭を抱えてしまう現象が発生したりします。


なので...

  • DLL外に公開する場合static readonly
  • 自分DLL内だけでしか使わない場合const

のスタンスで宣言したほうが安全かと思います。

本気でパフォーマンスが必要な場合constの方が実行効率はほんの少しだけconstの方がいいのでそういった場合もconstを指定することになります。
(まぁ、、、滅多にないと思いますが)


メソッドのデフォルト値もconstと同じ挙動になります。

public static void Foo(string str = "Default")
{
   // 省略

この場合呼び出し側で

public static void Main(string[] args)
{
    Hoge.Foo();
}

と呼び出して安心しててもコンパイル後に実際は

public static void Main(string[] args)
{
    Hoge.Foo("Default");
}

に置き換わってるので特に注意が必要です。
特に意識してない & 見えない & 便利なのでやりがちなんですが

こういったケースが困る場合、昔ながらの方法でオーバーロードを複数個定義したほうが幸せになれます。

まぁ配布しちゃったDLLの定数を後から変更するって事自体、何か計画性が無いとダメなんですがね・・・

広告を非表示にする