無謀にも、C#歴2週間でいきなりEffective C#(2nd Edition)から読みはじめています。この本のItem 23、"Understand How Interface Methods Difer from Virtual Methods"を読んで、メソッドの修飾子に「new」を使うという凄い例を初めて見たのでびっくりしました。
以下Effective C#からのコードの抜粋です。
interface IMsg { void Message(); } public class MyClass : IMsg { public void Message() { Console.WriteLine("MyClass"); } } public class MyDerivedClass : MyClass { public new void Message() { Console.WriteLine("MyDerivedClass"); } }
C#はメソッドが仮想(virtual)でないというのが言語仕様のポリシーなので、基底クラスでvirtual修飾子を付けないメソッドを派生クラスで再定義すると、基底クラスのメソッドが隠蔽されます(virtualとoverrideとは別)。しかし、このとき派生クラスのメソッド定義で修飾子としてnewを記述していないと、コンパイラが警告を発します(エラーではないので、気づかなかった)。
なんというか、C++の複雑な仕様をC#ではそのまま引き継いでしまったような感触を受けます。
さらにC#では、newというインスタンス生成のための予約語を、ぜんぜん違う意味に転用してしまっています*1。C#の言語仕様センスっていったいなんだろうか、ちょっと驚愕です。
ちなみに上記コードは、
MyDerivedClass d = new MyDerivedClass();
d.Message();
と実行するときは、"MyDerivedClass"と表示されますが、続いて
IMsg m = d as IMsg;
m.Message();
と基底クラスが実装するインタフェース型にas演算子で変換した場合は、"MyClass"とIMsgを実装した基底クラスのMessage()が実行されます。
Effective C#では、MyDerivedClassでインタフェースIMsgを再実装宣言することで、上記のインタフェース型に変換したとき派生クラスのMessage()を実行されるようにできると解説していました。
public class MyDerivedClass : MyClass, IMsg { ... }
ただし、基底型の変数に代入してMessage()を呼び出すと、基底型のMessage()が呼び出されます。これを、ポリモーフィズムに振舞わせるには、メソッドをvirtualにする必要があります。
(追記)new修飾子はメンバーどれにでも適用可能
基底クラスのvirtualなメソッドを派生クラスでnew付きでvirtualメソッドを再定義するとか、プロパティもnewで再定義するとか、メンバー変数にもnewで定義するとか、newを使えばなんでもあり、みたいな、あまりに強力かつ困惑する機能です。