명시적 인터페이스 구현(Explicit Interface Implementation)이란?
C#에서 하나의 클래스가 두 개의 인터페이스를 구현하는데, 두 인터페이스에 동일한 시그니처(메서드 이름과 매개변수가 같은 멤버)가 포함되어 있다면 어떻게 될까요? 일반적인 방식으로 해당 멤버를 구현하면, 두 인터페이스가 모두 이 단일 구현을 공유하게 됩니다.
이때 명시적 인터페이스 구현을 사용하면 문제를 해결할 수 있습니다. 명시적으로 구현된 멤버는 오직 해당 인터페이스 타입을 통해서만 호출할 수 있으며, 특정 인터페이스 전용으로 동작합니다. 즉, 각 인터페이스마다 서로 다른 독립적인 구현을 제공할 수 있습니다.
명시적 구현을 사용해야 하는 경우
- 두 개 이상의 인터페이스에 동일한 시그니처의 멤버가 존재하고, 각 인터페이스마다 다르게 동작해야 할 때
- 특정 멤버가 클래스의 public API로 외부에 노출되는 것을 막고, 인터페이스를 통해서만 접근 가능하게 하고 싶을 때
- 인터페이스 멤버의 이름 충돌을 피하면서 깔끔한 클래스 설계를 유지하고 싶을 때
예제 코드
아래 예제에서 ShowRoom 클래스는 ICar와 IBike라는 두 인터페이스를 구현하며, 두 인터페이스 모두 동일한 시그니처의 display() 메서드를 가지고 있습니다. 명시적 구현을 통해 각 인터페이스별로 별도의 메서드를 정의했습니다.
interface ICar
{
void display();
}
interface IBike
{
void display();
}
class ShowRoom : ICar, IBike
{
// ICar 인터페이스 전용 구현
void ICar.display()
{
throw new NotImplementedException();
}
// IBike 인터페이스 전용 구현
void IBike.display()
{
throw new NotImplementedException();
}
}
class Program
{
static void Main()
{
Console.ReadKey();
}
}
호출 방식 주의 사항
명시적으로 구현된 메서드는 클래스 인스턴스에서 직접 호출할 수 없습니다. 반드시 인터페이스 타입으로 형변환하여 호출해야 합니다.
ShowRoom room = new ShowRoom();
// room.display(); // 컴파일 오류 발생!
ICar car = room;
car.display(); // ICar의 display() 호출
IBike bike = room;
bike.display(); // IBike의 display() 호출
이처럼 명시적 인터페이스 구현은 인터페이스 간 멤버 충돌을 해결하고, 구현 세부 사항을 인터페이스 뒤로 숨겨 더 안전하고 명확한 객체 지향 설계를 가능하게 해줍니다.