반응형
- 이벤트를 구독하는 클래스에서 이벤트가 발생했을 때 어떤 처리를 하는 것을 이벤트 핸들러라고 함
- 이벤트를 구독하기 위해 += 연산자 사용
- 이벤트 구독을 해제하기 위해 -= 연산자 사용
- 이벤트를 구독, 등록, 가입, 추가, ... 등등으로 이해
- 이벤트를 발생시키는 클래스를 Publisher라 하고, 이벤트가 발생하면 처리하는 클래스를 Subscriber라고 함
.NET 지침을 따르는 이벤트를 게시하는 방법
.NET 지침을 따르는 이벤트 게시(C# 프로그래밍 가이드)
.NET 지침을 따르는 이벤트를 게시하는 방법을 알아봅니다. .NET 클래스 라이브러리의 모든 이벤트는 EventHandler 대리자를 기반으로 합니다.
docs.microsoft.com
// 이벤트 정보를 담을 클래스 정의
public class CustomEventArgs
{
public CustomEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
}
// 이벤트를 발행하는 클래스
class Publisher
{
// 닷넷에서 기본 제공하는 EventHandler<T> 대리자를 사용하여 이벤트 선언
public event EventHandler<CustomEventArgs> RaiseCustomEvent;
public void DoSomething()
{
// 이벤트 실행
OnRaiseCustomEvent(new CustomEventArgs("Event triggered"));
}
// 하위 클래스에서 재정의 가능한 메서드
protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
{
// 임시 변수에 이벤트 복사(Thread safety 때문)
EventHandler<CustomEventArgs> raiseEvent = RaiseCustomEvent;
e.Message += $" at {DateTime.Now}";
raiseEvent?.Invoke(this, e);
}
}
// 이벤트 구독 클래스
class Subscriber
{
private readonly string _id;
public Subscriber(string id, Publisher pub)
{
_id = id;
// 이벤트 구독
// pub.RaiseCustomEvent 이벤트에 이벤트 핸들러(HandleCustomEvent 메서드)를 구독
pub.RaiseCustomEvent += HandleCustomEvent;
}
// 이벤트 핸들러(실제 이벤트 처리)
void HandleCustomEvent(object sender, CustomEventArgs e)
{
Console.WriteLine($"{_id} received this message: {e.Message}");
}
}
var pub = new Publisher();
var sub1 = new Subscriber("sub1", pub);
var sub2 = new Subscriber("sub2", pub);
pub.DoSomething();
파생 클래스에서 기본 클래스 이벤트를 발생하는 방법
파생 클래스에서 기본 클래스 이벤트를 발생하는 방법 - C# 프로그래밍 가이드
파생 클래스에서 기본 클래스 이벤트를 생성하는 방법을 알아봅니다. 코드 예제를 살펴보고 사용 가능한 추가 리소스를 확인합니다.
docs.microsoft.com
// 이벤트 정보를 담을 클래스 정의
public class ShapeEventArgs
{
public ShapeEventArgs(double area)
{
NewArea = area;
}
public double NewArea { get; }
}
// 이벤트를 발행하는 클래스
public abstract class Shape
{
protected double _area;
public double Area
{
get => _area;
set => _area = value;
}
public event EventHandler<ShapeEventArgs> ShapeChanged;
public abstract void Draw();
protected virtual void OnShapeChanged(ShapeEventArgs e)
{
ShapeChanged?.Invoke(this, e);
}
}
public class Circle : Shape
{
private double _radius;
public Circle(double radius)
{
_radius = radius;
_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)
{
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)
{
_length = length;
_width = width;
_area = _length * _width;
}
public void Update(double length, double width)
{
_length = length;
_width = width;
_area = _length * _width;
OnShapeChanged(new ShapeEventArgs(_area));
}
protected override void OnShapeChanged(ShapeEventArgs e)
{
base.OnShapeChanged(e);
}
public override void Draw()
{
Console.WriteLine("Drawing a rectangle");
}
}
// 이벤트 구독 클래스
public class ShapeContainer
{
private readonly List<Shape> _list;
public ShapeContainer()
{
_list = new List<Shape>();
}
public void AddShape(Shape shape)
{
_list.Add(shape);
// shape.ShapeChanged 이벤트에 이벤트 핸들러(HandleShapeChanged 메서드)를 구독
shape.ShapeChanged += HandleShapeChanged;
}
private void HandleShapeChanged(object sender, ShapeEventArgs e)
{
if (sender is Shape shape)
{
Console.WriteLine($"Received event. Shape area is now {e.NewArea}");
shape.Draw();
}
}
}
var circle = new Circle(54);
var rectangle = new Rectangle(12, 9);
var container = new ShapeContainer();
container.AddShape(circle);
container.AddShape(rectangle);
circle.Update(57);
rectangle.Update(7, 7);
- Circle 클래스와 Rectangle 클래스는 Shape 클래스를 상속받고 있음
- circle 인스턴스 생성, container 인스턴스 생성(shape 들을 관리)
- container 인스턴스의 AddShape(circle) 메서드 호출 circle 인스턴스의 Shape.ShapeChanged 이벤트 구독
- circle 인스턴스의 Update 메서드 호출
- circle 인스턴스의 OnShapeChanged 메서드 호출
- circle 인스턴스의 Shape.OnShapeChanged 메서드 호출
- Shape.ShapeChanged 이벤트 실행
- Shape.ShapeChanged 이벤트에 구독한 이벤트 핸들러 호출
- container 인스턴스의 HandleShapeChanged 메서드(구독한 이벤트 핸들러) 호출
- 결과 출력
인터페이스 이벤트를 구현하는 방법
인터페이스 이벤트를 구현하는 방법 - C# 프로그래밍 가이드
클래스에서 인터페이스 이벤트를 구현하는 방법을 알아봅니다. 코드 예제를 살펴보고 사용 가능한 추가 리소스를 확인합니다.
docs.microsoft.com
public interface IDrawingObject
{
// 객체를 그리기 전에 이 이벤트를 발생시킴
event EventHandler OnDraw;
}
public interface IShape
{
// 객체를 그린 후에 이 이벤트를 발생시킴
event EventHandler OnDraw;
}
// 이벤트를 발행하는 클래스
public class Shape : IDrawingObject, IShape
{
event EventHandler PreDrawEvent;
event EventHandler PostDrawEvent;
object objectLock = new Object();
event EventHandler IDrawingObject.OnDraw
{
add
{
lock (objectLock)
{
PreDrawEvent += value;
}
}
remove
{
lock (objectLock)
{
PreDrawEvent -= value;
}
}
}
event EventHandler IShape.OnDraw
{
add
{
lock (objectLock)
{
PostDrawEvent += value;
}
}
remove
{
lock (objectLock)
{
PostDrawEvent -= value;
}
}
}
public void Draw()
{
// 객체가 그려지기 전에 IDrawingObject의 이벤트 발생
PreDrawEvent?.Invoke(this, EventArgs.Empty);
Console.WriteLine("Drawing a shape.");
// 객체가 그려진 후 IShape의 이벤트 발생
PostDrawEvent?.Invoke(this, EventArgs.Empty);
}
}
// IDrawingObject 참조
public class Subscriber1
{
public Subscriber1(Shape shape)
{
IDrawingObject d = (IDrawingObject)shape;
// IDrawingObject.OnDraw 이벤트에 이벤트 핸들러(d_OnDraw 메서드)를 구독
d.OnDraw += d_OnDraw;
}
void d_OnDraw(object sender, EventArgs e)
{
Console.WriteLine("Sub1 receives the IDrawingObject event.");
}
}
// IShape 참조
public class Subscriber2
{
public Subscriber2(Shape shape)
{
IShape d = (IShape)shape;
// IShape.OnDraw 이벤트에 이벤트 핸들러(d_OnDraw 메서드)를 구독
d.OnDraw += d_OnDraw;
}
void d_OnDraw(object sender, EventArgs e)
{
Console.WriteLine("Sub2 receives the IShape event.");
}
}
Shape shape = new Shape();
Subscriber1 sub = new Subscriber1(shape);
Subscriber2 sub2 = new Subscriber2(shape);
shape.Draw();
반응형
'C#' 카테고리의 다른 글
C# asyn, await (0) | 2021.12.27 |
---|---|
C# 확장 메서드 (0) | 2021.12.27 |
C# 대리자(Delegate), 무명 메서드, 람다식 (0) | 2021.12.26 |
C# 제네릭(Generic) (0) | 2021.12.24 |
C# string을 int로 변환 TryParse (0) | 2021.12.24 |