뇌를 자극하는 C# 4.0 프로그래밍/ 델리게이트와 이벤트

델리게이트란?

// 델리게이트 선언 방법
한정자 delegate 반환형식 델리게이트이름 (매개변수목록);

// 델리게이트 사용 예시
int Plus(int a, int b)
{
    return a + b;
}

int Minus(int a, int b)
{
    return a - b;
}

delegate int MyDelegate(int a, int b);
MyDelegate Callback;

Callback = new MyDelegate(Plus);
Console.WriteLine(Callback(3, 4));

Callback = new MyDelegate(Minus);
Console.WriteLine(Callback(7, 5));
  • C#에서 델리게이트는 콜백(Callback)을 구현하기 위해 사용된다.
  • 델리게이트는 메서드에 대한 참조이다.
  • 델리게이트에 메서드의 주소를 할당한 후 델리게이트를 호출하면 이 델리게이트가 메서드를 호출해 준다.
    • 델리게이트는 여러 메서드를 참조할 수 있기 때문에 –델리게이트 체인– 옵저버 패턴을 쉽게 구성할 수 있게 해준다.

델리게이트는 왜, 그리고 언제 사용하나요?

  • 값이 아닌 코드 자체를 매개변수로 넘기고 싶을 때 델리게이트를 사용한다.
    • 여러 곳에서 하나의 동일한 코드를 실행하는데, 코드 완료 후 각기 다른 메서드를 실행해야 하는 경우, 코드를 받는 입장에서 코드 로직은 같지만 자신의 코드를 완료한 후 실행해야 하는 메서드가 달라져 여러 메서드를 따로 만들어야 하는 중복 코드가 발생하게 된다.
    • 이 때 코드 완료 후에 실행해야 하는 각기 다른 메서드 자체를 매개변수로 넘겨주면 코드를 받는 입장에서는 자신의 코드를 완료한 후에 매개변수로 넘겨 받은 메서드를 실행해 버리면 되기 때문에 코드가 매우 간편해 진다.
    • 이런 역할을 하는게 바로 델리게이트이다. 매개변수로 메서드를 넘길 수 있게 해줘서 코드 중복을 줄이는 것.
    • 더불어 델리게이트는 델리게이트 체인을 이용하여 델리게이트에 등록된 여러 메서드들을 한번에 실행하게 하는 강력한 기능을 갖고 있는데, 이는 이벤트라는 기능으로 이어진다.
  • (매개변수를 넘기는 예시 생략)

일반화 델리게이트

// 일반화 델리게이트 사용 예시
delegate int Compare<T> (T a, T b);

static int AscendCompare<T> (T a, T b)
{
    return a.CompareTo(b);
}
  • 일반화 메서드와 동일하게 델리게이트도 일반화 할 수 있다.

델리게이트 체인

// 델리게이트 체인 사용 예시
void Call119 (string location)
{
    Console.WriteLine("소방서죠? 불났어요! 주소는 {0}", location);
}
void ShotOut (string location)
{
    Console.WriteLine("피하세요! {0}에 불이 났어요!", location);
}
void Escape (string location)
{
    Console.WriteLine("{0}에서 나갑시다!", location);
}

delegate void ThereIsAFire(string location);

// +를 이용해서 하나의 델리게이트에 여러 메서드를 넣을 수 있다.
ThereIsAFire fire = new ThereIsAFire(Call119);
fire += new ThereIsAFire(ShotOut);
fire += new ThereIsAFire(Escape);
  • 델리게이트는 하나가 여러 개의 메서드를 동시에 참조할 수 있다는 특징이 있다.
  • 하나의 델리게이트에 여러 메서드를 넣으려면 + 기호를 이용하면 된다.
  • 만일 델리게이트에 넣어진 메서드 중 하나를 제거해야 한다면 - 기호를 이용하면 된다.

익명 메서드

// 익명 메서드의 선언 방법
델리게이트 인스턴스 = delegate(매개변수목록)
                        {
                            // 실행 코드
                        }

// 익명 메서드 사용 예시
public static void Main()
{
    Calculate Calc;

    Calc = delegate(int a, int b)
            {
                return a + b;
            }

    Console.WriteLine("3 + 4: {0}", Calc(3, 4));
}
  • 델리게이트가 참조할 메서드를 넘겨야 할 일이 생겼는데 이 메서드를 두 번 사용할 일이 없다고 판단되면 위와 같이 메서드를 익명으로 만들어 사용하면 된다.

이벤트: 객체에 일어난 사건 알리기

// 이벤트가 발생했을 경우 그것을 구독자에게 알려줄 발행자 클래스.
// 발행자는 구독자가 누구인지 모르고 다만 구독자들에게 이벤트가 발생했을 시 그것을 알리는 역할만 한다.
class Publisher
{
    //이벤트를 위한 델리게이트 정의. 델리게이트 자체는 밖에 있어도 무방하다.
    public delegate void MyEventHandler();

    // 델리게이트에 event 한정자를 붙여서 이벤트를 정의한다.
    // 델리게이트 체인 기능을 이용하여 이벤트가 발생했을시 구독하는 객체들의 메서드를 모두 실행한다.
    public event MyEventHandler Click;

    // 이벤트 발생시 실행되는 메서드
    public void DoClick()
    {
        if(Click != null) // 이 객체의 이벤트를 구독하는 구독자가 있는지 검사
        {
            // 이벤트 발생. 구독자들에게 이벤트를 통지함.(델리게이트 호출)
            Click(); 
        }
    }
}

// 이벤트를 구독하는 구독자(Subscriber) 클래스 
// 이벤트가 발생했을시 그것을 들을지 말지는 각 클래스에서 스스로 정한다.
class Subscriber
{       
    static void Main()
    {
        // 이벤트 발행자 객체 생성
        Publisher p = new Publisher();

        // 이벤트를 구독한다. 
        // 이벤트가 발생했을시 실행할 자신의 메서드를 등록해 둔다.
        p.Click += new Publisher.MyEventHandler(p_Click);
    }

    // Publisher 객체에서 Click 이벤트가 발생할 때 호출되는 메서드
    // 델리게이트 호출을 통해 이 메서드를 이벤트에 등록해 둔다.
    // 이벤트 구독자는 여럿일 것이고, 발행자는 이벤트가 발생했을시 델리게이트 체인을 이용하여 각 구독자가 등록해 둔 메서드들을 모두 실행하게 된다.
    static void p_Click()
    {
        Console.WriteLine("Publisher 객체의 Click 이벤트가 발생하였습니다");
    }               
}
  • (책에 나온 설명보다 좀 더 잘 정리된 내용으로 정리. 이벤트는 publisher-subscriber 관계로 이해하는게 가장 명확하다. 발행자-구독자 관계로 보면 C#의 이벤트는 옵저버 패턴을 담고 있다고 할 수 있다.)
  • C#에서 이벤트는 델리게이트를 event 한정자로 수식해서 만든다. 이벤트가 델리게이트 형식인 이유는 이벤트가 발생했을 시 델리게이트 체인을 이용하여 이벤트 구독자들에게 한 번에 알리기 위함. 이벤트를 갖고 있는 클래스가 발행자가 된다.
  • 이벤트 구독자들은 이벤트가 발생했을 시 실행할 메서드를 이벤트에 등록해 두어서 이벤트가 실행되면 메서드가 자동으로 실행되게 한다.
  • 이벤트는 외부에서 실행시킬 수 없으며, 오로지 발행자만이 이벤트를 실행할 수 있다. 이벤트 구독자들은 이벤트가 발생했을시 실행할 메서드를 등록할 수만 있다. 이는 보안 관련 이슈인데 자세한 내용은 다음 섹션에서 설명.

델리게이트와 이벤트

  • 이벤트와 델리게이트의 가장 큰 차이점은 이벤트는 외부에서 직접 사용할 수 없다는 것. 반면 델리게이트는 외부에서 얼마든지 호출할 수 있다.
  • 이벤트가 외부에서 호출될 수 없다는 사실은 견고한 이벤트 기반 프로그래밍을 가능하게 한다. 이벤트는 발행자만 발생시킬 수 있기 때문에 –누구나 들을 수는 있지만– 신뢰할 수 있다.
[ssba]

The author

지성을 추구하는 디자이너/ suyeongpark@abyne.com

댓글 남기기

This site uses Akismet to reduce spam. Learn how your comment data is processed.