# delegate의 장점!
: 타입 안정적인 콜백을 정의할 수 있다.
: 여러 클래스가 상호 통신을 수행해야 할 때 클래스 간의 결합도를 낮추고 싶다면 인터페이스보다 델리게이트를 사용하는 것이 좋다.
: 런타임에 통지 대상을 설정할 수 있고, 다수의 클라이언트에게 통지를 보낼 수도 있다.
: 하나의 델리게이트는 여러 메서드에 대한 참조를 포함할 수 있기 때문이다.
# 자주 사용되는 delegate
.NET Framework 라이브러리는 Predicate<T>, Action<>, Func<>와 같은 형태로, 자주 사용되는 델리게이트를 정의해두고 있다.
. Predicate<T> : 조건을 검사하여 bool값을 반환하는 델리게이트.
(Func<T, bool> == Predicate<T>와 동일하다고 볼 수 있다.)
. Func<> : 여러 개의 매개변수를 받아 단일의 결과값을 반환하는 델리게이트.
. Action<> : 여러 개의 매개변수를 받지만 반환 타입이 void인 델리게이트.
# 멀티캐스트
모든 델리게이트는 기본적으로 멀티캐스트가 가능하다.
일반적으로 동일한 타입의 매개변수를 취하더라도 반환 타입이 다른 경우 서로 다른 델리게이트 타입으로 간주하며,
멀티캐스트 델리게이트는 한 번만 호출하면, 델리게이트 객체에 추가된 모든 대상 함수가 호출된다.
. 주의 1 : 예외 안전성이 좋지 않다.
멀티캐스트 델리게이트의 내부 동작 방식은 대상 함수들을 연속적으로 호출하는 형태로 구현된다.
델리게이트는 어떤 예외도 잡지 않으며, 따라서 예외가 발생하면 함수 호출 과정이 중단된다.
. 주의 2 : 마지막 호출 대상 함수의 반환값만이 델리게이트의 반환값이다.
1 2 3 4 5 6 7 8 9 10 11 12 | List<ComplicatedClass> container = new List<ComplicatedClass>(); public void LengthyOperation(Func<bool> pred) { foreach(ComplicatedClass cl in container) { cl.DoLengthyOperation(); if (false == pred()) // 사용자가 임의로 중단을 요청했는지 확인 return; } } | cs |
위 메서드를 멀티캐스트 델리게이트로 사용하면 문제가 발생한다.
1 2 3 4 5 | Func<bool> cp = () => CheckWithUser(); cp += () => CheckWithSystem(); c.LengthyOperation(cp); | cs |
델리게이트의 반환값은 체인 마지막으로 호출된 함수의 반환값이 되며, 다른 반환값은 모두 무시된다.
따라서 위의 예제의 경우 CheckWithUser( )의 반환값은 무시된다.
이러한, 문제를 해결하려면, 델리게이트에 포함된 호출 대상 콜백 함수를 직접 다뤄야한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public void LengtyOperation2(Func<bool> pred) { bool bContinue = true; foreach(ComplicatedClass cl in bContinue) { cl.DoLengthyOperation(); foreach (Func<bool> pr in pred.GetInvocationList()) bContinue &= pr(); if (!bContinue) return; } | cs |
위처럼 코드를 작성하면 델리게이트에 추가된 개별 메서드가 ture를 반환하는 경우에만 다음 메서드에 대한 호출을 이어갈 수 있다.
delegate 관련 글 : https://loveme-do.tistory.com/13
참 고 : Effective C#
'책 > Effective C#' 카테고리의 다른 글
Item 9. 박싱과 언박싱을 최소화하라. (0) | 2019.04.05 |
---|---|
Item 8. 이벤트 호출 시에는 null 조건 연산자를 사용하라. (0) | 2019.04.04 |
Item 6. nameof( ) 연산자를 적극 활용하라. (0) | 2019.01.31 |
Item 5. 문화권별로 다른 문자열을 생성하려면 FormattableString을 사용하라. (0) | 2019.01.30 |
Item 4. String.Format()을 보간 문자열로 대체하라. (0) | 2019.01.11 |