C# で Java の final と同等の制限をかける

Java プログラマが C# を学ぶ際のメモ。final については探しても見当たらなかったので書いておきます。

定数・フィールドのfinal

定数に対しては const 識別子, コンストラクタ値を設定する書き込み禁止フィールドについては readonly 識別子を使います。

class Foo {
    private const int NUM_MAX = 65535; // 定数値。コンストラクタでの遅延代入が不可。
    private readonly int _id; // 書き込み禁止値。コンストラクタで遅延代入が可能。

<pre><code>public Foo(int id){
    _id = id;
}
</code></pre>

}

メソッド中で、遅延代入をする方法はなさそうです。

public doSomething(){
    readonly int j = 1; // これはエラー。readonly はフィールドでのみ可能。
    const int N;
    N = 10; // これもエラー。const は宣言と同時に代入しなければならない。
}

同様に、引数の final (引数の変数への再代入禁止)を C# で利用することはできません。

public void doSomeThing2(const int number); // const は引数には適用不可

クラスのfinal

クラスに対しては、sealed 識別子が同等の効果をもちます。

sealed class FinalClass{ /* … */ }

メソッドのfinal

Java におけるメソッドの宣言に対しての final は、C# ではデフォルトの実装のため、ポリモーフィズムについては C# のほうが Java より制限的といえます。

final でない(オーバーライド可能な)メソッドを定義するには、親で virtual 識別子をつけて宣言し、かつ子で override 識別子で明示してオーバーライドします。

override 識別子をつけている場合、さらにその子クラスでも再帰的にオーバーライドが可能です。オーバーライド可能なメソッドに対して「オーバーライドした上で子には禁止する」という動作を実装する場合は、クラスと同様に sealed 識別子を利用します。

class Parent {
    public virtual void Greet(){ // オーバーライド可能
        Console.WriteLine(“Hello”);
    }
    public void StandUp(){ // オーバーライド禁止。オーバーライドしようとするとコンパイルエラー
        // …
    }
}

class Child : Parent {
    public override void Greet(){ // オーバーライド。明示しないとコンパイルエラー
        Console.WriteLine(“Hi!!”);
    }
}

class GrandChild : Child {
    public sealed override void Greet(){ // オーバーライド。ただし、このクラスの子にはオーバーライドを許さない。
    }
}

参考: