Home Full Site
C# 8 : 디폴트 인터페이스 멤버 구현 (Default Inteface Members)

지금까지 (C# 8.0 이전) C#에서 인터페이스를 한번 배포한 후, 그 인터페이스를 수정하면 기존에 구현된 모든 타입들을 수정하지 않는 한 타입 오류를 발생시켰다. 더구나 그 인터페이스를 외부에서 사용한다면, 수정은 거의 불가능하였다. C# 8.0에서는 인터페이스에 새로운 멤버를 추가하고, 새로운 멤버의 Body 구현 부분을 추가할 수 있게 되었다. 이렇게 새로 추가된 인터페이스 멤버는 디폴트로 사용되기 때문에, 기존 구현된 타입들이 새 멤버를 추가적으로 구현되지 않을 경우, 이 디폴트 구현을 사용하게 된다.

예를 들어, ILogger 인터페이스가 초기에 아래와 같이 정의되었다고 가정하자.

예제

// ILogger v1.0
public interface ILogger
{
    void Log(string message);
}


이후 새로운 기능이 필요해서 ILogger 인터페이스에 2개의 메서드를 추가한 ILogger v2.0을 출시한다고 가정하자. 즉, ILogger v2.0은 Exception 객체를 받아이거나 로그타입을 추가적으로 받아들일 수 있도록 한 것이다. 이때, 새로 추가된 메서드들에 디폴트 메서드 Body부분을 구현해서 기존 v1.0을 사용하는 타입들도 별도의 수정없이 계속 사용할 수 있도록 한다.

예제

// ILogger v2.0
public interface ILogger
{
    void Log(string message);

    // 추가된 멤버들
    void Log(Exception ex) => Log(ex.Message);
    void Log(string logType, string msg)
    {
        if (logType == "Error" ||
            logType == "Warning" ||
            logType == "Info")
        {
            Log($"{logType}: {msg}");
        }
        else
        {
            throw new ApplicationException("Invalid LogType");
        }
    }
}


물론 ILogger v2.0을 새로 구현하는 클래스는 디폴트 멤버 구현을 사용하지 않고 자신만의 구현을 재정의할 수 있다.

예제

class MyLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
        Debug.WriteLine(message);
    }

    // 디폴트 구현을 사용하지 않고 새로 정의함
    public void Log(Exception ex)
    {
        Debug.WriteLine(ex.ToString());
    }
}


한가지 주의할 점은 인터페이스의 디폴트 멤버 구현을 엑세스하기 위해서는 인터페이스로 캐스팅된 변수를 사용한다는 점이다. 예를 들어, 위 ILogger.Log(string logType, string msg) 메서드에서 정의된 디폴트 구현은 MyLogger 객체에서 직접 엑세스할 수 없고, ILogger로 캐스팅 된 후에 엑세스할 수 있다.
Use Default Interface Member
© csharpstudy.com