본문 바로가기

C#

C#의 확장 메서드는 언제 사용하면 좋을까?

확장 메서드가 뭔가요?

확장 메서드는 C#의 기능으로, 어떤 클래스에 외부에서 메서드를 정의해서 추가하는 것이다.

확장 메서드는 다음과 같이 정의된다.

SomeClass someClass = new SomeClass();
someClass.ExtensionMethod(42);	// someClass.A = 42

class SomeClass
{
    public int A;
}

static class SomeClassExtension
{
    public static void ExtensionMethod(this SomeClass s, int a)
    {
        s.A = a
    }
}

 

  1. 정적 클래스에
  2. 첫 번째 매개변수를 this로 선언할 것

이렇게 하면 첫 번째 매개변수로 지정한 클래스에 원래 그런 이름의 메서드가 있었던 것 처럼 메서드를 호출할 수 있다. 이는 정적 메서드의 문법적 설탕Syntactic Sugar이다. 그 말은 내부적으로는 일반 정적 메서드 호출과 같으며, 겉으로 보이는 문법만 다르다는 것이다. 실제로 아래의 두 문장은 완전히 동일하다.

someClass.ExtensionMethod(42);
SomeClassExtension.ExtensionMethod(someClass, 42);

 


좋은가?

확장 메서드는 정말 확장 메서드가 이득이 되는 경우라고 판단되는 경우가 아니면 자제하는 것이 좋다. 확장 메서드는 기본적으로 읽기 어렵다. 만든 사람 자신이 아니면 어떻게 사용해야 하는지 파악하기 어려운 것이 보통이며, 만든 사람 본인도 시간이 흐르면 잊어버릴 가능성이 크다.

 

그래서 확장 메서드는 일반적인 유틸리티 메서드나 헬퍼 메서드의 용도가 아니라, 말 뜻 그대로 어느 한 클래스의 기능을 확장해주는 용도로 사용하는 것이 가장 알맞다. 다른 방식으로 표현하면, 원래 그 클래스에 있었어도 이상하지 않았을 것 같은 메서드에 적용하기에 알맞다.

 

확장 메서드를 사용하면 좋은 일반적인 경우는 다음과 같다.

  1. 다른 라이브러리/어셈블리에 있는 메서드에 기능을 추가하고 싶을 때
  2. 인터페이스에 일관적인 기능을 제공하고 싶을 때
  3. 메서드 체이닝을 사용하고 싶을 때

정도로 요약할 수 있다. 이러한 명확한 목적이 있지 않으면 사용하지 않는 것을 권한다.

 

1,2,3을 모두 만족하는 대표적인 예는 System.Linq이다. 

LINQ에서 흔히 사용하는 Select, Where 등의 메서드의 경우 모두 IEnumerable의 확장 메서드인데, System.Collectons.Generic에 정의된 IEnumerable을 건드리지 않고도 System.Linq에서 IEnumerable의 기능을 확장하고 있다. 또한 IEnumerable이라면 어디에든지 적용할 수 있어서 사용자 정의 IEnumerable에게도 모두 사용할 수 있는 등 확장성이 매우 뛰어나다. 또한 LINQ는 문법 특성상 메서드 체이닝과 잘 어울린다. 확장 메서드를 사용한 가장 바람직한 예라고 볼 수 있다.


결론

확장 메서드는 정말로 어느 클래스의 기능을 확장하는 곳에 쓰면 클래스의 단일 책임 원칙을 잘 지키면서도 다양한 기능을 쉽게 추가할 수 있고, 코드를 사용하는 사람에게도 읽기 쉽고 직관적인 코드를 만들어 줄 수 있는 좋은 기능이다.

그러나 남용하면 이 메서드의 출처가 어디인지 한눈에 보이지 않아 읽기 어려워질 수 있으므로 주의해서 사용해야 한다.


사족..

유니티를 사용하다 보면 FindChiildByName 이라던가 GetOrAddComponent 같은 이름의 헬퍼 메서드를 만들게 되는 일이 매우 흔하다. 이런 것들은 일반 정적 메서드가 읽기 쉬울까? 아니면 확장 메서드가 읽기 쉬울까? 고민되는 지점이다. 개인적으로는 정말 범용적인 것들에 한정해서 확장메서드로 제공해도 괜찮다고 생각된다.