* 정의

 

인터페이스는 C#에서 사용되는 추상화하기 위해 사용되는 도구이다. 추상 클래스와 비슷하지만 일반적으로 구현부가 없는 메소드, 이벤트, 인덱서, 프로퍼티만을 가질 수 있고 인터페이스를 상속받은 클래스에서 이 기능들을 구현하도록 되어있다. 접근 제한 한정자를 사용할 수 없으며 모든 것이 public으로 선언된다.

 

// C# 8.0부터 멤버의 구현부가 있을 수도 있고 4가지 이 외에 다른 것들을 멤버로 가질 수 있게 되었다.

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface

 

interface - C# Reference

:::no-loc text=interface::: (C# Reference)

docs.microsoft.com

 

 

* 사용 이유

 

  • 기본 구현이 없다면 인터페이스를 상속받은 클래스는 이 기능들을 반드시 구현하도록 강제하기 위해 사용된다. // 기본 구현 기능은 C# 8.0부터 지원하고 있다.
  • 인터페이스는 실제 구현 내용이 없기 때문에 죽음의 다이아몬드 문제가 발생하지 않는다. 덕분에 다중 상속을 할 수 있으며 이는 유연한 개발 환경을 제공한다.
  •  구조체는 ildasm으로 확인했을 때 sealed 클래스인데 구조체가 유일하게 상속받을 수 있는 클래스는 인터페이스이다.
  • 특정한 세부 구현을 숨길 수 있다.

 

 

* 동작 방식

 

- 멤버 선언

 

인터페이스에서 멤버를 선언하면 abstract와 public 키워드가 자동으로 붙게 된다. 따라서 public 접근 제한 한정자를 붙이지 않아도 되는 것이고, abstract 키워드 덕분에 상속받은 클래스에서 구현을 강제할 수 있는 것이다.

 

 

C# 8.0부터는 기본 구현을 가질 수 있으며 기본 구현을 작성하면 abstract 키워드가 붙지 않는다. 따라서 상속받은 클래스에서 반드시 구현하지 않아도 된다.

 

 

- 상속 받은 클래스에서 구현과 이를 다시 상속 받은 클래스

 

상속 받는 클래스에서 구현 시 override 키워드를 따로 붙이지 않아도 된다. 구현된 멤버는 ildasm으로 봤을 때 final 키워드가 붙어 있다. 이 때문에 새로운 클래스에 인터페이스를 구현한 클래스를 상속해도 이미 구현된 인터페이스의 멤버를 오버라이딩할 수 없다. // 그렇다고 컴파일 에러가 발생하는 것은 아니다. 일반적인 함수 선언으로 간주된다.

 

< 호출 코드 >

InterfaceTest test = new InterfaceTest2();
test.DoSomething(); // 오버라이딩 되지 않기 때문에 InterfaceTest의 DoSomething이 호출된다.

 

 

- 여러 인터페이스를 상속받은 경우

 

여러 인터페이스를 상속받을 때 메소드 이름이 같은 경우도 존재한다. 그럴 때는 인터페이스를 명시적으로 구현하면 된다.

다음 코드는 제네릭 컬렉션 List을 직접 구현해 본 코드의 일부이다. GetEnumerator, Current가 상속 받은 인터페이스에 모두 존재하여서 명시적으로 구현하였다.

public class MyList<T> : IEnumerable<T>, IEnumerable
{
    IEnumerator<T> IEnumerable<T>.GetEnumerator() { return new MyList<T>.Enumerator(this, count); }
    IEnumerator IEnumerable.GetEnumerator() { return new MyList<T>.Enumerator(this, count); }

    // ...
    // ...

    public struct Enumerator : IEnumerator<T>, IEnumerator
    {
        T IEnumerator<T>.Current { get { return parent[position]; } }
        object IEnumerator.Current { get { return parent![position]!; } }
        // ...
        // ...
    }
}

 

 

- 특징

 

  • 추상 클래스와 비슷하게 객체를 생성할 수 없다. 
  • 기본 구현을 제외하면 구현부를 가지지 않고 구현부는 상속받은 클래스에서 작성한다.
  • 인터페이스를 상속받은 클래스에서 기본 구현이 없는 모든 멤버를 반드시 오버라이딩하여 구현해야 한다.
  • 클래스의 인스턴스와 관련된 필드를 포함할 수 없다.
  • 생성자를 포함할 수 없다.

 

 

- 개인적인 생각

 

인터페이스는 추상 클래스와 다르게 필드와 같은 인스턴스와 관련된 정보를 담을 수 없다.

 

그렇기 때문에 인터페이스를 상속 받는다는 것은 개인적으로 계층 구조를 표현한다기 보다 동작(기능)들을 정의하기 위해 사용되는 느낌을 받았다.

 

인터페이스는 어떤 객체가 어떠한 동작(기능)을 할 수 있는 지 다중 상속을 통해 유연하게 제공한다고 생각한다. 이러한 유연성 덕분에 Unity의 컴포넌트 기반 설계처럼 전반적인 계층 구조를 신경 쓰지 않고 빠르게 확장해 나갈 수 있는 것 같다.

 

 

* abstract class vs interface

 

https://create-new-worlds.tistory.com/348

 

[C#] abstract class vs interface

* abstract class vs interface abstract class interface 다중 상속 불가능하다. 가능하다. 필드(field) // 인스턴스와 관련있는 것들 포함할 수 있다. 일반적으로 포함할 수 없다. // C# 8.0부터 인스턴스와 관..

create-new-worlds.tistory.com

 

'C#' 카테고리의 다른 글

[C#] dynamic  (0) 2022.07.06
[C#] Generic Collection 구현 해보기  (0) 2022.07.01
[C#] abstract  (0) 2022.06.28
[C#] abstract class vs interface  (0) 2022.06.28
[C#] const, readonly  (0) 2022.06.28

+ Recent posts