2014-10-08

[C#] extension method - 존재하는 class 확장하기.

 지난 글에서 이미 존재하는 class에 새로운 함수를 추가해주는 Scala의 implicit class라는 기능을 소개했다. Scala의 implicit class는 라이브러리에서 제공해주어 내가 수정할 수 없는 class를 확장할 때 유용하게 사용되며, 코드의 일관성을 유지하기 위해 원래 class에는 최소한의 기능만을 구현하고, 추가적인 구현은 종류별로 여러 implicit class를 구현하는 방식으로 사용되기도 한다. class의 선언과 구현 detail을 분리할 수 있게 해주는 여러모로 재밌는 기능이다.

 C#은 이런 기능을 extension method라는 방식으로 구현하였다.
 Extension method가 없던 시절(사실 없던 시절은 꽤 오래전 이야기다. Extension method가 유명하지 않아서 그렇지 vs2008부터 들어갔던 기능이다.)에는 확장하고 싶은 class를 상속받아 새로운 class를 만들거나, wrapper class를 만들거나, static method를 만들어 객체를 넘기는 방식으로 구현하여야 했다.
 하지만 이런 방식들은 전부 문제가 있다. 우선 상속으로 새로운 class를 구현하는 방법은 확장할 클래스가 sealed class일 경우 사용하지 못한다. wrapper class를 만드는 방법은 새로 만드는 함수 이외에 다른 함수들을 wrapper class로 연결해 주어야 해서 코드가 매우 boilerplate 해진다. 무엇보다 이 두 방법은 모두 하고자 하는 일에 비해 너무 많은 코드를 작성해야 한다. 마지막 static method를 만드는 방법은 함수를 호출하는 모양이 달라서 코드의 일관성이 없어진다.
 하지만 extension method를 사용하면 이런 문제를 쉽게 해결할 수 있다.

 Extension method를 정의하는 것은 간단하다. 확장하고자 하는 method를 static class의 static method로 정의하면서 첫 번째 인자에 this modifier를 붙이면 된다.
 전체적으로 작업할 코드의 양은 static method를 만들어서 Random 객체를 인자로 넘기는 함수를 만드는 것과 크게 다르지 않다. 단순히 'this'라는 4글자의 modifier가 추가된 정도이다. 이렇게 extension method를 정의하면 첫 번째 parameter가 instance로 쓰이고 나머지 인자들은 함수의 인자로 사용된다.

 C# library 중 extension method를 사용하는 대표적인 라이브러리는 Linq다. Linq는 IEnumerable을 extension method로 확장하여 C#의 IEnumerable을 상속받는 collection들을 전부 일관된 형식으로 사용할 수 있게 해줬다.

 앞에서 말했듯이 extension method라는 기능이 c#에 들어간 지는 매우 오래됐다. 하지만 존재 자체를 모르는 사람들도 많다. 왜냐하면, extension method를 사용하는 것이 장려되지 않기 때문이다. MSDN의 guide 문서에서도 가능하면 상속을 이용하고, 최대한 extension method 사용을 피하라고 말하고 있다. Extension method를 너무 남용하면, 오히려 가독성이 떨어지게 되기 때문이다.
 그래서 Linq처럼 하나의 Domain-specific language(a.k.a. DSL)을 새로 만들어야 하는 경우가 아니면 잘 쓰이지 않는다.

댓글 2개:

  1. 난 일단 enum의 메소드를 정의하는 거 딱 하나로 쓰고 있어.
    class 같은 느낌이 나서 표현력이 살짝 좋아지는듯.
    그나저나 scala 글 보면서 왠지 이 얘기도 나올 거 같더니 정말 나오는군.

    답글삭제
    답글
    1. 헤헤 내가 쫌 뻔함.
      그러게 enum이 상속받지 못해서 extension method로 확장시키는 MSDN에서 추천하는 몇 안되는 사례인데 언급하는 것을 깜빡했군. 감사요.

      삭제