C#의 delegate 이해와 람다식

대리자는 특정 매개 변수 목록 및 반환 형식이 있는 메서드에 대한 참조를 나타내는 형식입니다. 대리자를 인스턴스화하면 모든 메서드가 있는 인스턴스를 호환되는 시그니처 및 반환 형식에 연결할 수 있습니다. 대리자 인스턴스를 통해 메서드를 호출할 수 있습니다

이렇게 보면 뭔 말인지 이해가 쉽지 않은데, 직접 다뤄보니 C의 함수포인터와 매우 유사하다는 느낌이다,

대리자는 메서드를 다른 메서드에 인수로 전달하는 데 사용됩니다.

이 설명이 delegate의 핵심이라고 생각한다.

1. delegate는 어떤 경우에 사용하면 좋은가?

피호출 클래스에서 호출 클래스의 특정 메서드를 호출하고 싶을 때 매번 호출 클래스를 인자로 받아오지 않아도 된다. delegate를 활용하면 클래스간 결합이 interface 보다 더 느슨해져서 메서드 형식만 맞으면 어떤 클래스의 어떤 메서드를 대입하더라도 사용할 수 있다.

2. delegate 선언하기

  • 컴파일러가 검증할 수 있도록 메서드의 인자와 리턴값을 선언한다.
  • 메서드 선언 중 메서드명에 해당하는 부분은 C의 typedef로 별칭(새로운 형식)을 정의하는 것과 동일한 용법으로 생각할 수 있다.
delegate int PerformCalculation(int x, int y);

3. delegate 할당하기

위의 코드에 의해 PerformCalculation라는 형식이 생겼다. 이제 이 형식으로 사용할 변수 p를 생성한다. 변수라고 한 이유는 p에 할당하는 메서드는 형식만 맞으면 어느 것이든지 사용할 수 있기 때문이다.

// 어딘가에 있는 int Add(int x, int y) 메서드를 대입한다.
// static 메서드도, new로 생성한 instance의 메서드도 가능하다.
PerformCalculation p = Add;

4. 메서드를 호출하자

PerformCalculation p로 정의한 p를 내부메서드(함수)를 호출하듯 호출한다. p.Add()로 호출하는 것이 아님에 유의한다.

int result = p(1, 2);

5. 그밖의 활용법

// void 리턴형식의 delegate를 선언한다. 리턴값이 꼭 void여야 한다.
delegate void DelegateChain(int x, int y);
DelegateChain p += method1;
DelegateChain p += method2;
DelegateChain p += method3;

p(1, 2);
  • 결과는 method1, method2, method3가 순서대로 실행된다.
  • 마찬가지로 -= 연산자로 실행 목록에서 메서드를 제거할 수 있으며, +=으로 추가하지 않은 메서드를 -=으로 빼더라도 런타임 오류는 발생하지 않는다.
  • 윈폼의 이벤트는 delegate로 구성되어 있다. 사용자가 +=으로 메서드를 추가해 두면 이벤트가 발생했을 때 메서드를 등록한 순서대로 호출한다.
  • 참고사이트: http://tapito.tistory.com/45

6. 무명메서드

  • C# 2.0부터는 delegate만으로도 간단하게 무명메서드를 정의할 수 있다. 이후에 등장할 람다를 추천한다.
  • 자바는 익명클래스(=무명클래스)의 메서드 오버라이드를 통해 비슷하게 구현할 수 있는데 C#보다는 조금 더 많은 코딩이 필요하다. 자바도 8이후 도입된 람다를 사용하는 것을 추천.
delegate int delegateMethod(int a);
delegateMethod m = null;

// 어딘가에 있는 메서드가 아니라 코드 중간에 메서드를 구현했다
m = delegate(int a) { return a++; };
int result1 = m(1);

m = delegate(int a) { return a--; };
int result2 = m(2);

7. 람다표현식

이왕 여기까지 온 거, C# 3.0부터 도입된 람다도 다루어 보자.

delegate int delegateMethod(int a);
delegateMethod m = null;

// 람다 표현식
m = a => a++;
int result1 = m(1);

끝.