인터페이스의 암묵적 구현과 명시적 구현

[제목] 인터페이스의 암묵적 구현과 명시적 구현

C#에서 클래스는 하나의 Base 클래스와 여러 개의 Interface들을 상속/구현할 수 있다. 클래스는 인터페이스가 지정된 경우 이 인터페이스가 갖는 메서드들을 모두 구현해야 한다. 메서드를 구현하는 방법은 암묵적 구현(Implicit Implementation)과 명시적 구현(Explicit Implementation) 으로 나눌 수 있다.

(주: 이 글은 편의상 메서드에 촛점을 맞추어 설명하지만, Property, Event 등 인터페이스 멤버들에 동일한 규칙이 적용됨)

Visual Studio에서 인터페이스명에서 Rightclick 하면 선택된 구현방법에 맞게 메서드 템플릿을 삽입해 준다.



암묵적 구현은 메서드를 public 클래스 멤버로 구현하고, 명시적 구현은 메서드를 private 멤버로 [인터페이스명.메서드명] 형식으로 메서드명을 표시한다. 예를 들어, 아래 IAction 인터페이스 예에서 Act() 메서드는 암묵적 구현으로, React() 메서드는 명시적으로 구현하고 있다.

public interface IAction
{
    void Act();
    void React();
}

public class Person : IAction
{
    public void Act()
    {            
    }

    void IAction.React()
    {         
    }
}
그렇다면 이렇게 다른 구현 방식은 C#에서 사용할 때 어떤 영향을 미치는가? 암묵적 구현은 클래스의 public 메서드로 구현되기 때문에, 클래스 객체 레퍼런스를 통해 해당 public 메서드를 호출할 수 있다. 하지만, 명시적으로 구현된 메서드의 경우 private 멤버로 클래스 객체 레퍼런스로부터 접근할 수 없다. 즉, 아래에서 처럼 React() 메서드는 Person 클래스 객체 p로부터 엑세스할 수 없다. 이 React() 메서드를 호출하려면 먼저 인터페이스 레퍼런스를 얻은 후에 (혹은 캐스팅 한 후에) 호출하여야 한다.
public class App
{
    public void Run()
    {
        Person p = new Person();
        p.Act();
        p.React(); // 컴파일 에러

        // 인터페이스 통한 접근
        IAction itf = p;
        itf.Act();    // OK
        itf.React(); // OK

        // 인터페이스 캐스팅
        ((IAction)p).React(); // OK
    }
}
이러한 차이점은 클래스가 인터페이스를 구현하더라도 인터페이스의 모든 메서드들을 public으로 노출할 필요가 없는 경우에 유용할 수 있다. 즉, 적어도 개발자가 필요한 메서드만을 선택하여 노출할 수 있도록 한다. 또한, 경우에 따라 반드시 명시적 인터페이스명을 써야하는 경우도 있다. 만약 여러 개의 (외부) 인터페이스를 한 클래스가 구현한다고 했을 때, 그리고 이들 인터페이스의 메서드명이 동일한 경우에 한 클래스는 복수 개의 동일한 메서드명을 가져야 한다. 이런 경우 각 인터페이스별로 [인터페이스.메서드명] 형식으로 다른 메서드를 구현할 수 있다. 아래 예는 Act()라는 메서드를 갖는 2개의 인터페이스를 구현하는 Person 클래스를 보여 준다.
public interface IAct {
    void Act();
}

public interface IRun {
    void Act();
}

public class Person : IAct, IRun {
    public void Act()
    {
        Console.WriteLine("A");
    }

    void IAct.Act()
    {
        Console.WriteLine("B");
    }

    void IRun.Act()
    {
        Console.WriteLine("C");
    }
}
class Program
{
    static void Main(string[] args)
    {
        Person p = new Person();
        p.Act();             // A
        ((IAct)p).Act();   // B
        ((IRun)p).Act();  // C
    }
}
동일한 메서드 Act()는 각 인터페이스별 그리고 해당 클래스 소속 메서드로 서로 다른 3개의 메서드로 구현되어 있으며, 예제에서 처럼 서로 다른 호출 방법을 통해 각각 다른 메서드를 엑세스할 수 있다.


본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.