선택한 부분을 인쇄합니다. 클립보드로 복사합니다. 강좌의 전체내용을 선택합니다.
hoons닷넷
[ C#.NET 고급강좌]
  델리게이트 200% 활용하기 - Func, Action
 작성자 : 김수영  작성일 : 2009-08-13 오전 2:54:06
 E-mail : dotnethelper골뱅이gmail.com  Homepage : http://www.dotnetngene.kr
2009년 6월호로 월간 마이크로소프트웨어에 기고한 기사입니다. 


 
 우리가 프로그램을 작성할 때 많이 사용하게 되는 것 중 하나가 델리게이트(delegate, 대리자 혹은 위임)일 것이다. 델리게이트는 이벤트핸들러(event handler) 등록, 콜백(callback) 메서드 정의, 그리고 메서드(method)의 파라미터(parameter)로 전달 등 많은 곳에서 쓰이고 있다. 특히 메서드의 파라미터로 사용할 경우 아주 유연한 개발이 가능하다. 닷넷 프레임워크(.NET Framework) 3.5 LINQ에서 Where 확장메서드(Extension Method)의 경우처럼, 여러 조건으로 필터링하는 메소드를 만든다고 가정해 보자. 검색 조건은 상황에 따라 아주 다양할 것이다. 그럼 모든 상황별 메서드를 모두 만들 것인가? 사실상 불가능 하다. 그래서 Where 확장메서드는 필터링을 처리하는 델리게이트를 파라미터 받을 수 있게 되어있다. 필요한 그때 그때 필터링하는 기능을 만들어서 델리게이트로 넘기면 된다. 기능 구현은 닷넷프레임워크 2.0의 익명메서드(Anonymous Method)나 닷넷프레임워크 3.5의 람다식(Lambda Expressions)를 통해 명시적 메서드 구현 없이도 쉽게 사용 가능하다. 여기서 또 한가지 의문을 가질 수 있다. 실제적은 기능 구현은 익명메서드나 람다식으로 하면 되지만 정작 Where 같은 메서드를 정의할 때 쓰일 델리게이트는 어떻게 할 것인가? 다양한 파리미터 조건을 가지고 싶다면? 그에 맞게 델리게이트를 명시적으로 모두 정의할 것인가? 이 또한 쉽지 않다. 그래서 닷넷프레임워크 3.5에서는 이런 고민들 쉽게 해결할 특수(?) 델리게이트를 지원해 주고 있다. 바로 “Func”와 “Action” 델리게이트이다. 이들 델리게이트는 [표 1]과 [표 2]에서 보는 것처럼 제네릭(generic) 타입으로 정의되어 있으며, 몇 가지 유형으로 오버라이드(override) 되어 있어 다양한 요구 조건을 모두 만족 할 수 있다. “Func”와 “Action” 의 차이점은 위임된 기능이 처리되고 반환되는 결과값이 있느냐, 없느냐의 차이만 있다.

Func : 내부 처리 완료 후 반환되는 결과값이 있음. 특정 조건으로 필터링하고 그 결과를 반환하는 Where 같은 메소드를 구현할 때 쓰면 유용할 것이다.

Action : 내부 처리 완료 후 반환되는 결과값이 없음. 어떤 처리 진행을 보여 주는 UI 업데이트 같은 처리를 할 때 유용할 것이다.

delegate void Action <T> (T arg) 는 이미 닷넷프레임워크 2.0에 존재 하였으며 다른 델리게이트들과 다르게 mscorlib(mscorlib.dll) 어셈블리에 정의되어 있다(네임스페이스는 동일하게 System에 존재한다).
 
[정의]
네임스페이스:  System
어셈블리:  System.Core (System.Core.dll)



[표 1] Action 델리게이트
delegate void Action ( );
delegate void Action <T> (T arg);
delegate void Action <T1, T2> (T1 arg1, T2 arg2);
delegate void Action <T1, T2, T3> (T1 arg1, T2 arg2, T3 arg3);
delegate void Action <T1 ,T2, T3, T4> (T1 arg1, T2 arg2, T3 arg3, T4 arg4);



[표 2] Func 델리게이트
delegate TResult Func <TResult> ( );
delegate TResult Func <T, TResult> (T arg);
delegate TResult Func <T1, T2, TResult> (T1 arg1, T2 arg2);
delegate TResult Func <T1, T2, T3, TResult> (T1 arg1, T2 arg2, T3 arg3);
delegate TResult Func <T1, T2, T3, T4, TResult> (T1 arg1, T2 arg2, T3 arg3,T4 arg4);


예를 하나 살펴 보자. 숫자로 구성된 배열이 존재하고, 다양한 조건으로 배열에서 값을 가져오는 메서드를 정의하고 싶다고 가정하자. 여기서는 “다양한 조건으로 검색이 가능하도록”이 중요한 포인트이다. 검색을 다양하게 하려면 호출되는 시점에 필터링 조건을 주면 된다. 해당값이 조건이 맞는지 확인해서 bool 형식을 반환하는 코드가 필요하므로 “Func”를 사용하여 [코드1]과 같이 메소드를 정의 하였다.

[코드 1] 숫자 배열에서 여러 조건으로 필터링 할 수 있는 메서드 정의

private static List<int> FilterOfInts(int[] source, Func<int, bool> filter) {
    List<int> result = new List<int>();
    foreach (int i in source) { if (filter(i)) { result.Add(i); } }
    return result;
}


이제 정의된 메서드를 통해, 명시적으로 정의된 메서드 혹은 익명메서드, 람다식 모두를 사용하여 원하는 결과를 볼 수 있다. [코드 2]를 보면 FilterOfInts를 모두 호출하지만 람다식으로 다양한 조건을 파라미터로 넘기고 있다. 각 조건에 맞는 메소드를 모두 구현하는 것이 아니라 단일 메소드를 호출 하므로 보다 유연한 모듈 개발이 가능한 것을 확인 할 수 있다.


[코드 2] FilterOfInts를 통한 다양한 필터 조건을 사용

int[] source = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//===홀수 Filter===
List<int> oddNumbers = FilterOfInts(source, i => ((i & 1) == 1));
//===짝수 Filter===
List<int> evenNumbers = FilterOfInts(source, i => ((i & 1) == 0));
//===소수 Filter===
List<int> primeNumbers = FilterOfInts(source,
    checkNumber => {
        BitArray numbers = new BitArray(checkNumber + 1, true);
        for (int i = 2; i < checkNumber + 1; i++) {
          if (numbers[i]) {
            for (int j = i * 2; j < checkNumber + 1; j += i) { numbers[j] = false; }
        if (numbers[i]) { if (checkNumber == i) { return true; } }
          }
        }
        return false;
})

평점: 9.3/10 (8명 참여)   
트랙백 주소 : http://www.hoons.kr/25856/BoardTrackback.aspx ()
등록된 트랙백 0

나도한마디
사용자
글등록 +1288  덧글등록 +1566
귀뫄뉘            [2009-09-10]
Level 41
 [EXP.46/100]
눈에 잘 익지 않은 코드였는데 덕분에 많이 익숙해진것 같습니다. 감사합니다 ^^
사용자
글등록 +121496  덧글등록 +14664
엔젤루스            [2009-09-18]
Level 99
 [EXP.만랩]
데...델리게이트 맨날 봐도 어려운 부분 ㅜㅜ
사용자
글등록 +121152  덧글등록 +11490
레몬소다            [2009-09-28]
Level 58
 [EXP.189/250]
어려워요 ~ ㅎㅎ
사용자
글등록 +1272  덧글등록 +124
가을의전설            [2009-09-29]
Level 11
 [EXP.0/40]
쉽지가 않네요... 열공밖에는 없는 듯...^^
사용자
글등록 +12132  덧글등록 +1155
goni            [2009-11-17]
Level 19
 [EXP.32/70]
잡힐듯 말듯... 어려워~
사용자
글등록 +12200  덧글등록 +12462
화랑            [2009-12-21]
Level 73
 [EXP.96/250]
와 감사합니다.
사용자
글등록 +120  덧글등록 +16
한인규            [2010-01-11]
Level 2
 [EXP.2/16]
마지감 줄에 ; 요놈이 빠져있네요. 첨에 잘못된 코드인줄 알고 조금 해멨다는..(저만 그런건가요???)
사용자
글등록 +120  덧글등록 +12
빼주            [2010-01-28]
Level 1
 [EXP.6/16]
....봐도봐도 정말어렵네요 ㅜㅜ
사용자
글등록 +120  덧글등록 +17
악마개발자            [2010-02-12]
Level 2
 [EXP.5/16]
너무 어려운 델리게이트 ㅠㅠ
사용자
글등록 +120  덧글등록 +121
빵꾸똥꾸            [2010-02-23]
Level 4
 [EXP.15/16]
델리게이트는 아무리 이해를 다한다해도 무궁무진해서..도무지 감이 안잡힌다는.......ㅜ.ㅜ
사용자
글등록 +120  덧글등록 +168
しろたん            [2010-02-23]
Level 12
 [EXP.14/40]
역시 공부가 필요해..
사용자
글등록 +120  덧글등록 +16
투팍            [2010-03-12]
Level 2
 [EXP.2/16]
감사합니다.
사용자
글등록 +12108  덧글등록 +1242
블루아사            [2010-05-24]
Level 23
 [EXP.17/50]
어렵네요..;;
사용자
글등록 +1248  덧글등록 +1384
ryan            [2010-06-08]
Level 30
 [EXP.36/50]
흠....델리게이트 써보긴 했는데....막상 다시보니....
내공이 딸리는 군여.... ㅡ.,ㅡㅋ