* 정의
인터페이스는 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 |