인터페이스 - 여러 형식에 대한 동작 정의

인터페이스에는 비추상 클래스 class 또는 struct이(가) 구현해야 하는 관련 기능 그룹에 대한 정의가 포함되어 있습니다. 인터페이스에서는 구현이 있어야 하는 static 메서드를 정의할 수 있습니다. 인터페이스는 멤버에 대한 기본 구현을 정의할 수 있습니다. 인터페이스에서는 필드, 자동 구현 속성, 속성과 유사한 이벤트 등과 같은 인스턴스 데이터를 선언할 수 없습니다.

예를 들어 인터페이스를 사용하면 여러 소스의 동작을 클래스에 포함할 수 있습니다. 해당 기능은 언어가 클래스의 여러 상속을 지원하지 않기 때문에 C#에서 중요합니다. 또한 구조체는 다른 구조체나 클래스에서 실제로 상속할 수 없기 때문에 구조체에 대한 상속을 시뮬레이트하려는 경우 인터페이스를 사용해야 합니다.

다음 예제와 같이 interface 키워드를 사용하여 인터페이스를 정의합니다.

interface IEquatable<T>
{
    bool Equals(T obj);
}

인터페이스 이름은 유효한 C# 식별자 이름이어야 합니다. 규칙에 따라 인터페이스 이름은 대문자 I로 시작합니다.

IEquatable<T> 인터페이스를 구현하는 모든 클래스나 구조체에는 인터페이스에서 지정한 서명과 일치하는 Equals 메서드에 대한 정의가 포함되어 있어야 합니다. 따라서 IEquatable<T>을 구현하는 클래스를 계산하여 클래스의 인스턴스에서 동일한 클래스의 다른 인스턴스와 동일한지 여부를 확인할 수 있는 Equals 메서드를 포함할 수 있습니다.

IEquatable<T>의 정의에서는 Equals에 대한 구현을 제공하지 않습니다. 클래스 또는 구조체는 여러 인터페이스를 구현할 수 있지만 클래스는 단일 클래스에서만 상속할 수 있습니다.

추상 클래스에 대한 자세한 내용은 추상 및 봉인 클래스와 클래스 멤버를 참조하세요.

인터페이스에는 인스턴스 메서드, 속성, 이벤트, 인덱서 또는 이러한 네 가지 멤버 형식의 조합이 포함될 수 있습니다. 인터페이스에는 정적 생성자, 필드, 상수 또는 연산자가 포함될 수 있습니다. C# 11부터는 필드가 아닌 인터페이스 멤버는 static abstract일 수 있습니다. 인터페이스에는 인스턴스 필드, 인스턴스 생성자 또는 종료자가 포함될 수 없습니다. 인터페이스 멤버는 기본적으로 공용이며, public, protected, internal, private, protected internal 또는 private protected 등의 접근성 한정자를 명시적으로 지정할 수 있습니다. private 멤버에는 기본 구현이 있어야 합니다.

인터페이스 멤버를 구현하려면 구현 클래스의 해당 멤버가 공용이고 비정적이어야 하며 인터페이스 멤버와 동일한 이름 및 서명을 사용해야 합니다.

참고 항목

인터페이스가 정적 멤버를 선언하는 경우 해당 인터페이스를 구현하는 형식은 동일한 서명을 가진 정적 멤버를 선언할 수도 있습니다. 멤버는 이를 선언하는 형식에 의해 구분되고 고유하게 식별됩니다. 형식에서 선언된 정적 멤버는 인터페이스에서 선언된 정적 멤버를 재정의하지 않습니다.

인터페이스를 구현하는 클래스 또는 구조체는 인터페이스에서 제공하는 기본 구현 없이 선언된 모든 멤버에 대한 구현을 제공해야 합니다. 그러나 기본 클래스에서 인터페이스를 구현하는 경우에는 기본 클래스에서 파생되는 모든 클래스가 해당 구현을 상속합니다.

다음 예제에서는 IEquatable<T> 인터페이스의 구현을 보여 줍니다. 구현 클래스 CarEquals 메서드의 구현을 제공해야 합니다.

public class Car : IEquatable<Car>
{
    public string? Make { get; set; }
    public string? Model { get; set; }
    public string? Year { get; set; }

    // Implementation of IEquatable<T> interface
    public bool Equals(Car? car)
    {
        return (this.Make, this.Model, this.Year) ==
            (car?.Make, car?.Model, car?.Year);
    }
}

클래스의 속성 및 인덱서는 인터페이스에 정의된 속성이나 인덱서에 대해 추가 접근자를 정의할 수 있습니다. 예를 들어 인터페이스는 get 접근자가 있는 속성을 선언할 수 있습니다. 인터페이스를 구현하는 클래스는 getset 접근자를 둘 다 사용하는 동일한 속성을 선언할 수 있습니다. 그러나 속성 또는 인덱서에서 명시적 구현을 사용하는 경우에는 접근자가 일치해야 합니다. 명시적 구현에 대한 자세한 내용은 명시적 인터페이스 구현인터페이스 속성(C# 프로그래밍 가이드)을 참조하세요.

인터페이스는 하나 이상의 인터페이스에서 상속할 수 있습니다. 파생 인터페이스는 기본 인터페이스에서 멤버를 상속합니다. 파생 인터페이스를 구현하는 클래스는 파생 인터페이스의 기본 인터페이스 멤버 모두를 포함해 파생 인터페이스의 모든 멤버를 구현해야 합니다. 이 클래스는 파생 인터페이스나 해당하는 기본 인터페이스로 암시적으로 변환될 수 있습니다. 클래스는 상속하는 기본 클래스 또는 다른 인터페이스에서 상속하는 인터페이스를 통해 인터페이스를 여러 번 포함할 수 있습니다. 그러나 클래스는 인터페이스의 구현을 한 번만 제공할 수 있으며 클래스가 인터페이스를 클래스 정의의 일부로 선언하는 경우에만 제공할 수 있습니다(class ClassName : InterfaceName). 인터페이스를 구현하는 기본 클래스를 상속했기 때문에 인터페이스가 상속되는 경우 기본 클래스는 인터페이스 멤버의 구현을 제공합니다. 그러나 파생 클래스는 상속된 구현을 사용하는 대신 가상 인터페이스 멤버를 다시 구현할 수 있습니다. 인터페이스가 메서드의 기본 구현을 선언하면 해당 인터페이스를 구현하는 모든 클래스가 해당 구현을 상속합니다(인터페이스 멤버의 기본 구현에 액세스하려면 클래스 인스턴스를 인터페이스 형식으로 캐스팅해야 합니다).

또한 기본 클래스는 가상 멤버를 사용하여 인터페이스 멤버를 구현할 수 있습니다. 이 경우 파생 클래스는 가상 멤버를 재정의하여 인터페이스 동작을 변경할 수 있습니다. 가상 멤버에 대한 자세한 내용은 다형성을 참조하세요.

인터페이스 요약

인터페이스에는 다음과 같은 속성이 있습니다.

  • 8.0 이전 C# 버전에서 인터페이스는 추상 멤버만 있는 추상 기본 클래스와 유사합니다. 인터페이스를 구현하는 클래스 또는 구조체는 해당 멤버를 모두 구현해야 합니다.
  • C# 8.0부터 인터페이스에서 해당 멤버 일부 또는 모두의 기본 구현을 정의할 수 있습니다. 인터페이스를 구현하는 클래스 또는 구조체는 기본 구현이 있는 멤버를 구현할 필요가 없습니다. 자세한 내용은 기본 인터페이스 메서드를 참조하세요.
  • 인터페이스는 직접 인스턴스화할 수 없습니다. 해당 멤버는 인터페이스를 구현하는 클래스 또는 구조체에 의해 구현됩니다.
  • 클래스 또는 구조체는 여러 인터페이스를 구현할 수 있습니다. 클래스는 기본 클래스를 상속할 수 있으며 하나 이상의 인터페이스를 제공할 수도 있습니다.