다음을 통해 공유


방법: 파생 클래스에서 기본 클래스 이벤트 발생(C# 프로그래밍 가이드)

다음의 간단한 예제에서는 기본 클래스의 이벤트를 선언할 때 해당 이벤트가 파생 클래스에서도 발생할 수 있도록 하는 일반적인 방법을 보여 줍니다. 이 패턴은 .NET Framework 클래스 라이브러리의 Windows Forms 클래스에서 광범위하게 사용됩니다.

다른 클래스의 기본 클래스로 사용할 수 있는 클래스를 만드는 경우 이벤트는 이를 선언한 클래스 내에서만 호출할 수 있는 특별한 형식의 대리자라는 사실을 염두에 두어야 합니다. 파생 클래스는 기본 클래스 내에서 선언된 이벤트를 직접 호출할 수 없습니다. 일부 경우에는 기본 클래스에 의해서만 발생시킬 수 있는 이벤트가 필요하기도 하지만, 대부분의 경우에는 파생 클래스에서 기본 클래스 이벤트를 호출할 수 있도록 해야 합니다. 이렇게 하려면 기본 클래스에서 이벤트를 래핑하는 보호 호출 메서드를 만듭니다. 이 호출 메서드를 호출하거나 재정의하면 파생 클래스에서 이벤트를 간접적으로 호출할 수 있습니다.

참고

기본 클래스에 가상 이벤트를 선언하고 파생 클래스에서 이를 재정의하지 마십시오.C#컴파일러핸들이 정확 하 게 수행 하며 파생 된이벤트에 대 한 구독자를기본 클래스이벤트에 실제로 가입 하는 것인지 예측할 수 없습니다.

예제

namespace BaseClassEvents
{
    using System;
    using System.Collections.Generic;

    // Special EventArgs class to hold info about Shapes. 
    public class ShapeEventArgs : EventArgs
    {
        private double newArea;

        public ShapeEventArgs(double d)
        {
            newArea = d;
        }
        public double NewArea
        {
            get { return newArea; }
        }
    }

    // Base class event publisher 
    public abstract class Shape
    {
        protected double area;

        public double Area
        {
            get { return area; }
            set { area = value; }
        }
        // The event. Note that by using the generic EventHandler<T> event type 
        // we do not need to declare a separate delegate type. 
        public event EventHandler<ShapeEventArgs> ShapeChanged;

        public abstract void Draw();

        //The event-invoking method that derived classes can override. 
        protected virtual void OnShapeChanged(ShapeEventArgs 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<ShapeEventArgs> handler = ShapeChanged;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    }

    public class Circle : Shape
    {
        private double radius;
        public Circle(double d)
        {
            radius = d;
            area = 3.14 * radius * radius;
        }
        public void Update(double d)
        {
            radius = d;
            area = 3.14 * radius * radius;
            OnShapeChanged(new ShapeEventArgs(area));
        }
        protected override void OnShapeChanged(ShapeEventArgs e)
        {
            // Do any circle-specific processing here. 

            // Call the base class event invocation method. 
            base.OnShapeChanged(e);
        }
        public override void Draw()
        {
            Console.WriteLine("Drawing a circle");
        }
    }

    public class Rectangle : Shape
    {
        private double length;
        private double width;
        public Rectangle(double length, double width)
        {
            this.length = length;
            this.width = width;
            area = length * width;
        }
        public void Update(double length, double width)
        {
            this.length = length;
            this.width = width;
            area = length * width;
            OnShapeChanged(new ShapeEventArgs(area));
        }
        protected override void OnShapeChanged(ShapeEventArgs e)
        {
            // Do any rectangle-specific processing here. 

            // Call the base class event invocation method. 
            base.OnShapeChanged(e);
        }
        public override void Draw()
        {
            Console.WriteLine("Drawing a rectangle");
        }

    }

    // Represents the surface on which the shapes are drawn 
    // Subscribes to shape events so that it knows 
    // when to redraw a shape. 
    public class ShapeContainer
    {
        List<Shape> _list;

        public ShapeContainer()
        {
            _list = new List<Shape>();
        }

        public void AddShape(Shape s)
        {
            _list.Add(s);
            // Subscribe to the base class event.
            s.ShapeChanged += HandleShapeChanged;
        }

        // ...Other methods to draw, resize, etc. 

        private void HandleShapeChanged(object sender, ShapeEventArgs e)
        {
            Shape s = (Shape)sender;

            // Diagnostic message for demonstration purposes.
            Console.WriteLine("Received event. Shape area is now {0}", e.NewArea);

            // Redraw the shape here.
            s.Draw();
        }
    }

    class Test
    {

        static void Main(string[] args)
        {
            //Create the event publishers and subscriber
            Circle c1 = new Circle(54);
            Rectangle r1 = new Rectangle(12, 9);
            ShapeContainer sc = new ShapeContainer();

            // Add the shapes to the container.
            sc.AddShape(c1);
            sc.AddShape(r1);

            // Cause some events to be raised.
            c1.Update(57);
            r1.Update(7, 7);

            // Keep the console window open in debug mode.
            System.Console.WriteLine("Press any key to exit.");
            System.Console.ReadKey();
        }
    }
}
/* Output:
        Received event. Shape area is now 10201.86
        Drawing a circle
        Received event. Shape area is now 49
        Drawing a rectangle
 */

참고 항목

참조

이벤트(C# 프로그래밍 가이드)

대리자(C# 프로그래밍 가이드)

액세스 한정자(C# 프로그래밍 가이드)

개념

C# 프로그래밍 가이드

기타 리소스

Windows Forms에서 이벤트 처리기 만들기