.NET 지침을 따르는 이벤트를 게시하는 방법(C# 프로그래밍 가이드)

다음 절차에서는 표준 .NET 패턴을 따르는 이벤트를 클래스와 구조체에 추가하는 방법을 보여 줍니다. .NET 클래스 라이브러리의 모든 이벤트는 다음과 같이 정의된 EventHandler 대리자를 기반으로 합니다.

public delegate void EventHandler(object? sender, EventArgs e);

참고 항목

.NET Framework 2.0에서는 이 대리자의 제네릭 버전인 EventHandler<TEventArgs>가 도입되었습니다. 다음 예제에서는 두 버전을 사용하는 방법을 모두 보여 줍니다.

정의하는 클래스의 이벤트는 값을 반환하는 대리자를 포함하여 유효한 모든 대리자 형식을 기반으로 할 수 있지만, 다음 예제와 같이 EventHandler를 사용하여 .NET 패턴에 따라 이벤트를 만드는 것이 좋습니다.

이름 EventHandler는 이벤트를 실제로 처리하지는 않으므로 약간의 혼동을 일으킬 수 있습니다. EventHandler 및 제네릭 EventHandler<TEventArgs>는 대리자 형식입니다. 시그니처가 대리자 정의와 일치하는 메서드 또는 람다 식은 이벤트 처리기이며, 이벤트가 발생할 때 호출됩니다.

EventHandler 패턴에 따라 이벤트 게시

  1. 이벤트와 함께 사용자 지정 데이터를 보낼 필요가 없는 경우 이 단계를 건너뛰고 3a 단계로 이동합니다. 게시자 및 구독자 클래스 둘 다에 표시되는 범위에서 사용자 지정 데이터에 대한 클래스를 선언합니다. 그런 다음 사용자 지정 이벤트 데이터를 저장하는 데 필요한 멤버를 추가합니다. 이 예제에서는 간단한 문자열이 반환됩니다.

    public class CustomEventArgs : EventArgs
    {
        public CustomEventArgs(string message)
        {
            Message = message;
        }
    
        public string Message { get; set; }
    }
    
  2. EventHandler<TEventArgs>의 제네릭 버전을 사용하는 경우 이 단계를 건너뜁니다. 게시 클래스에서 대리자를 선언합니다. EventHandler로 끝나는 이름을 지정합니다. 두 번째 매개 변수는 사용자 지정 EventArgs 형식을 지정합니다.

    public delegate void CustomEventHandler(object? sender, CustomEventArgs args);
    
  3. 다음 단계 중 하나를 사용하여 게시 클래스에서 이벤트를 선언합니다.

    1. 사용자 지정 EventArgs 클래스가 없는 경우 이벤트 유형은 제네릭이 아닌 EventHandler 대리자가 됩니다. C# 프로젝트를 만들 때 포함된 System 네임스페이스에서 이미 선언되었기 때문에 대리자를 선언할 필요는 없습니다. 게시자 클래스에 다음 코드를 추가합니다.

      public event EventHandler? RaiseCustomEvent;
      
    2. 제네릭이 아닌 버전의 EventHandler를 사용 중이고 EventArgs에서 파생된 사용자 지정 클래스가 있는 경우 게시 클래스 내에서 이벤트를 선언하고 2단계의 대리자를 형식으로 사용합니다.

      public event CustomEventHandler? RaiseCustomEvent;
      
    3. 제네릭 버전을 사용하는 경우에는 사용자 지정 대리자가 필요하지 않습니다. 대신, 게시 클래스에서 이벤트 유형을 EventHandler<CustomEventArgs>로 지정하고 고유한 클래스 이름을 꺾쇠 괄호로 묶어 대체합니다.

      public event EventHandler<CustomEventArgs>? RaiseCustomEvent;
      

예시

다음 예제에서는 사용자 지정 EventArgs 클래스와 EventHandler<TEventArgs>를 이벤트 유형으로 사용하여 이전 단계를 보여 줍니다.

namespace DotNetEvents
{
    // Define a class to hold custom event info
    public class CustomEventArgs : EventArgs
    {
        public CustomEventArgs(string message)
        {
            Message = message;
        }

        public string Message { get; set; }
    }

    // Class that publishes an event
    class Publisher
    {
        // Declare the event using EventHandler<T>
        public event EventHandler<CustomEventArgs>? RaiseCustomEvent;

        public void DoSomething()
        {
            // Write some code that does something useful here
            // then raise the event. You can also raise an event
            // before you execute a block of code.
            OnRaiseCustomEvent(new CustomEventArgs("Event triggered"));
        }

        // Wrap event invocations inside a protected virtual method
        // to allow derived classes to override the event invocation behavior
        protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<CustomEventArgs>? raiseEvent = RaiseCustomEvent;

            // Event will be null if there are no subscribers
            if (raiseEvent != null)
            {
                // Format the string to send inside the CustomEventArgs parameter
                e.Message += $" at {DateTime.Now}";

                // Call to raise the event.
                raiseEvent(this, e);
            }
        }
    }

    //Class that subscribes to an event
    class Subscriber
    {
        private readonly string _id;

        public Subscriber(string id, Publisher pub)
        {
            _id = id;

            // Subscribe to the event
            pub.RaiseCustomEvent += HandleCustomEvent;
        }

        // Define what actions to take when the event is raised.
        void HandleCustomEvent(object? sender, CustomEventArgs e)
        {
            Console.WriteLine($"{_id} received this message: {e.Message}");
        }
    }

    class Program
    {
        static void Main()
        {
            var pub = new Publisher();
            var sub1 = new Subscriber("sub1", pub);
            var sub2 = new Subscriber("sub2", pub);

            // Call the method that raises the event.
            pub.DoSomething();

            // Keep the console window open
            Console.WriteLine("Press any key to continue...");
            Console.ReadLine();
        }
    }
}

참고 항목