C#で複数のインターフェースを実装しつつ抽象クラスを継承する際、メソッド名が衝突するときの解決方法を整理します。
前提となる型定義
public interface ILeft
{
void Execute();
}
public interface IRight
{
void Execute();
}
public abstract class BaseRunner
{
public abstract void Execute();
}
パターン1:抽象クラスを継承+明示的実装を利用
public sealed class MultiRunner : BaseRunner, ILeft, IRight
{
// BaseRunner.Execute() をオーバーライド
public override void Execute()
{
Console.WriteLine("BaseRunner.Execute");
}
// ILeft.Execute() を明示的実装
void ILeft.Execute()
{
Console.WriteLine("ILeft.Execute");
}
// IRight.Execute() は BaseRunner.Execute と同一視
// 明示的実装を省略すると BaseRunner.Execute が呼ばれる
}
この構成では BaseRunner.Execute が IRight.Execute も兼ねるため、IRight 用の明示的実装は不要です。
パターン2:抽象クラスを継承しない場合
public sealed class StandaloneRunner : ILeft, IRight
{
// 通常の public メソッド(ILeft / IRight 両方に見える)
public void Execute()
{
Console.WriteLine("StandaloneRunner.Execute");
}
// ILeft 専用の実装
void ILeft.Execute()
{
Console.WriteLine("ILeft.Execute");
}
// IRight 専用の実装
void IRight.Execute()
{
Console.WriteLine("IRight.Execute");
}
}
抽象クラスを継承しない場合、override は使用できません。代わりに public 修飾子を付けたメソッドを用意することで、インターフェース実装のデフォルト実装として機能させられます。
呼び出し側での違い
var runner = new MultiRunner();
ILeft asLeft = runner;
IRight asRight = runner;
BaseRunner baseRef = runner;
asLeft.Execute(); // "ILeft.Execute"
asRight.Execute(); // "BaseRunner.Execute"
baseRef.Execute(); // "BaseRunner.Execute"
runner.Execute(); // "BaseRunner.Execute"
注意点まとめ
- 明示的インターフェース実装にはアクセス修飾子を付けられない(常に private)
- 抽象クラスを継承している場合、同名メソッドは
overrideで一本化できる - 継承していない場合、各インターフェースごとに明示的実装を書くか、共通の public メソッドを用意する
- 呼び出し側が保持する型によって実行される実装が変わる