반응형

http://www.gpgstudy.com/forum/viewtopic.php?p=95504&sid=3186560b92d188fe3fab7bef907f0c67

delegate하고 event하고 뭐가 다른지 잘 몰라서 그러는데요. 


class Test
{
    public delegate void Handler(string msg);
 
    public event Handler Event;
    public Handler Delegate;
 
    public void DoIt()
    {
        Event("event");
        Delegate("delegate");
    }
};
 
class Program
{
    static void MyFunc(string caller)
    {
        Console.WriteLine("Message from {0}", caller);
    }
     
    static void Main(string[] args)
    {
        Test test = new Test();
        test.Event += MyFunc;
        test.Delegate += MyFunc;
        test.DoIt();
    }

}

이 코드를 보면 event나 delegate이나 차이가 없어 보이는데 
혹시 제가 모르는 차이점이 있나요?







저도 예전에 차이점이 궁금했었는데요.. 
겉으로 보기에 용법이 같아서 그렇지 event와 delegate는 다른 놈입니다. 

event와 delegate를 
property와 멤버 변수의 관계랑 비슷하다고 생각하시면 됩니다. 

event는 property가 get, set을 갖는 것 처럼 add, remove함수를 가져야 합니다. 
근데 사용하기 쉽게 add, remove를 생략하실수 있습니다. 


public event Handler Event;  // 생략형



그냥 이렇게 하면 아래와 같은 코드가 만들어집니다. 


private Handler _Event; // _Event라는 delegate 변수를 자동으로 만들어냅니다.
public event Handler Event
{
    add
    {
        lock(this) { _Event += value; }
    }
 
    remove
    {
        lock(this) { _Event -= value; }
    }

}


이 Event 이벤트 변수에다가 +=을 써주면 add가 불리고 -=을 써주면 remove가 불리는 겁니다. 
그래서 겉에서 봤을땐 delegate랑 사용법이 똑같이 보이게 됩니다. 

근데 이것도 약간 다른 점이 이벤트 호출시에 Event("event");를 사용하는데 
이건 클래스 안에서만 사용 가능합니다. 클래스 밖에서 test.Event("event"); 하면 에러가 나지요 
생략형으로 쓰면 c#이 자동으로 Event() 호출을 _Event 대리자의 호출로 치환해 줍니다. 
_Event는 내부 변수이므로 밖에서 호출이 불가능합니다. 

add, remove를 명시적으로 쓸 경우에는 Event("event"); 이런식으로 호출을 못합니다(자동으로 대리자 변수를 만들어내지 않기 때문에) 
직접 _Event("event"); 이런식으로 대리자를 호출해 주거나 그에 상응하는 작업을 구현해야 합니다. 

이러한 차이점이 있기 때문에 event는 interface에서 선언해 줄수 있고요.. delegate는 그렇지 못합니다. 

event변수가 넘쳐나는걸 막기 위해 winforms에서는 메시지 이벤트를 add, remove를 직접 구현하고 dictionary에 event를 저장하는 방식을 쓴다고 합니다. 
http://msdn2.micros...ibrary/z4ka55h8.aspx
 

여기 Events 부분에 자세한 설명이 있습니다. 
http://www.yoda.ara...m/csharp/events.html





https://msdn.microsoft.com/ko-kr/library/z4ka55h8.aspx


방법: 사전을 사용하여 이벤트 인스턴스 저장(C# 프로그래밍 가이드)

각 이벤트에 대해 필드를 할당하는 대신 사전을 사용하여 이벤트 인스턴스를 저장하는 방법으로 많은 이벤트를 노출할 때 accessor-declarations를 사용할 수 있습니다. 이 방법은 많은 이벤트를 사용할 수 있지만 대부분의 이벤트가 구현되지 않을 것으로 예상할 때만 유용합니다.

public delegate void EventHandler1(int i);
public delegate void EventHandler2(string s);

public class PropertyEventsSample
{
    private System.Collections.Generic.Dictionary<string, System.Delegate> eventTable;

    public PropertyEventsSample()
    {
        eventTable = new System.Collections.Generic.Dictionary<string, System.Delegate>();
        eventTable.Add("Event1", null);
        eventTable.Add("Event2", null);
    }

    public event EventHandler1 Event1
    {
        add
        {
            lock (eventTable)
            {
                eventTable["Event1"] = (EventHandler1)eventTable["Event1"] + value;
            }
        }
        remove
        {
            lock (eventTable)
            {
                eventTable["Event1"] = (EventHandler1)eventTable["Event1"] - value;
            }
        }
    }

    public event EventHandler2 Event2
    {
        add
        {
            lock (eventTable)
            {
                eventTable["Event2"] = (EventHandler2)eventTable["Event2"] + value;
            }
        }
        remove
        {
            lock (eventTable)
            {
                eventTable["Event2"] = (EventHandler2)eventTable["Event2"] - value;
            }
        }
    }

    internal void RaiseEvent1(int i)
    {
        EventHandler1 handler1;
        if (null != (handler1 = (EventHandler1)eventTable["Event1"]))
        {
            handler1(i);
        }
    }

    internal void RaiseEvent2(string s)
    {
        EventHandler2 handler2;
        if (null != (handler2 = (EventHandler2)eventTable["Event2"]))
        {
            handler2(s);
        }
    }
}

public class TestClass
{
    public static void Delegate1Method(int i)
    {
        System.Console.WriteLine(i);
    }

    public static void Delegate2Method(string s)
    {
        System.Console.WriteLine(s);
    }

    static void Main()
    {
        PropertyEventsSample p = new PropertyEventsSample();

        p.Event1 += new EventHandler1(TestClass.Delegate1Method);
        p.Event1 += new EventHandler1(TestClass.Delegate1Method);
        p.Event1 -= new EventHandler1(TestClass.Delegate1Method);
        p.RaiseEvent1(2);

        p.Event2 += new EventHandler2(TestClass.Delegate2Method);
        p.Event2 += new EventHandler2(TestClass.Delegate2Method);
        p.Event2 -= new EventHandler2(TestClass.Delegate2Method);
        p.RaiseEvent2("TestString");

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
}
/* Output:
    2
    TestString 

*/

반응형

+ Recent posts