以下のようなクラス構造を作るとどう動作するのか、ちょっと自信が無かったので確認。
// 基底クラスであるインターフェースを実装
public class Animal : IHogerable
{
public void DoHoge()
{
Console.WriteLine("Animal");
}
}
// 派生クラスで同じインターフェースを実装
public class Dog : Animal, IHogerable
{
// new は無くても動作は同じ。new が無い場合は警告が出る。
public new void DoHoge()
{
Console.WriteLine("Dog");
}
}
public interface IHogerable
{
void DoHoge();
}
これらを IHogerable
型の変数経由で呼び出すとどうなるか?
もちろん、Animal
型の変数や Dog
型の変数経由で呼び出した場合はそれぞれのメソッドが呼ばれる。
var animal = new Animal();
animal.DoHoge(); // Animal.DoHoge が呼ばれる
var dog = new Dog();
dog.DoHoge(); // Dog.DoHoge が呼ばれる
foreach (var hogerable in new IHogerable[] { animal, dog })
{
hogerable.DoHoge(); // どっちのメソッドが呼ばれる???
}
Animal
Dog
Animal
Dog
IHogerable
型の変数経由で呼び出した場合、インスタンスの型に応じて呼び出されるメソッドが変わる。
なお、Dog
クラスの宣言で明示的に : IHogerable
を書くか書かないかで動作が変わる。
public class Dog : Animal // IHogerable の実装を宣言しない
{
public new void DoHoge() // 単に Animal.DoHoge の実装を隠ぺいする
{
Console.WriteLine("Dog");
}
}
こうすると
Animal
Dog
Animal
Animal
IHogerable
経由で呼び出した場合に Animal.DoHoge
の方が呼ばれるようになる。
つまり、Dog
クラスで IHogerable
の実装を上書きする意図があるかないかをくみ取ってくれる。
よく考えられているなぁ……
さらに確認した内容を追記します。
Q. インターフェースに複数のメンバーが定義されている場合は?
A. Dog
で隠ぺいした分はそちらが、隠ぺいしていない分は Animal
のメンバーが呼び出されます(つまり一部だけを隠ぺいすることが可能)
Q. Animal
クラスで暗黙的な実装と明示的な実装の両方がある場合は?
A. IHogerable
型経由で Dog
インスタンスのメンバーを呼び出した場合、以下の優先順で呼ばれます。直感通りです
-
Dog
クラスの明示的実装 -
Dog
クラスの隠ぺいしている暗黙的実装 -
Animal
クラスの明示的実装 -
Animal
クラスの暗黙的実装