Favicon

Event modifier

Peponi11/27/20244m

C#
SyntaxKeywordModifier

1. Introduction

event 한정자는 객체에서 사건이 발생했을 때 다른 객체에 알려주는 역할을 한다. 특수한 종류의 멀티캐스트 대리자로 여러 객체에서 구독하는 것이 가능하다.

event의 처리는 메서드 또는 람다 식을 통해 정의한다. 액세스 한정자를 적용할 수 있으며, 파생 클래스에서 상속받아 재정의 하는 것이 가능하다.

event는 GUI 및 비동기식 로직 처리 등에 활용된다.

2. Example

Declare & invoke event
public class FooArgs : EventArgs
{
    public FooArgs(int a) => A = a;
 
    public int A { get; set; }
}
 
public class Pub
{
    public event EventHandler<FooArgs> FooEvent;
 
    public void Foo() => FooEvent?.Invoke(this, new FooArgs(10));
}
Subscribe event
public class Sub
{
    Pub Pub;
 
    public Sub(Pub pub)
    {
        Pub = pub;
 
        // Subscribe
        Pub.FooEvent += BarEventHandler;
    }
 
    private void BarEventHandler(object sender, FooArgs e) => Console.WriteLine(e.A);
 
    // Cancel subscribe
    public void CancelSubscribe() => Pub.FooEvent -= BarEventHandler;
}

3. 파생 클래스에서 event 호출

event는 파생 클래스에서는 직접 호출이 불가능하다. (CS0070) 이 때, 부모 클래스의 event를 호출하기 위해 간접적인 방법을 사용할 수 있다.

Declare & invoke event
public class FooArgs : EventArgs
{
    public FooArgs(string message) => Message = message;
 
    public string Message { get; set; }
}
 
public class Pub
{
    public event EventHandler<FooArgs> FooEvent;
 
    protected virtual void RaiseFoo(FooArgs e) => FooEvent?.Invoke(this, e);
}
Derived class
public class PubD : Pub
{
    public PubD()
    {
        // FooEvent?.Invoke(this, new FooArgs("PubD"));    // CS0070
    }
 
    public void SendMessage(string message) => RaiseFoo(new FooArgs(message));
 
    // override method
    protected override void RaiseFoo(FooArgs e) => base.RaiseFoo(e);
}
internal class Program
{
    private static void Main()
    {
        PubD d = new PubD();
        d.FooEvent += D_FooEvent;
        d.SendMessage("PubD");
    }
 
    private static void D_FooEvent(object? sender, FooArgs e) => Console.WriteLine(e.Message);
}

4. Event override

eventvirtual, abstract 등을 이용해 여러 활용을 할 수 있다. 아래는 virtual을 이용한 override 예시를 보여준다.

Base class
public class FooArgs : EventArgs
{
    public FooArgs(string message) => Message = message;
 
    public string Message { get; set; }
}
 
public class Pub
{
    public virtual event EventHandler<FooArgs> FooEvent;
 
    public virtual void Foo() => FooEvent?.Invoke(this, new FooArgs("Pub"));
}
Derived class
public class PubE : Pub
{
    public override event EventHandler<FooArgs> FooEvent
    {
        add { base.FooEvent += value; Console.WriteLine("PubE event add"); }
        remove { base.FooEvent -= value; Console.WriteLine("PubE event remove"); }
    }
}
 
public class PubFoo : Pub
{
    public override event EventHandler<FooArgs> FooEvent;
 
    public override void Foo() => FooEvent?.Invoke(this, new FooArgs("PubFoo"));
}
Test
internal class Program
{
    private static void Foo_FooEvent(object? sender, FooArgs e) => Console.WriteLine($"{sender} sent a message : {e.Message}");
 
    private static void Main()
    {
        Pub pub = new Pub();
        pub.FooEvent += Foo_FooEvent;
        pub.Foo();                                     // Program+Pub sent a message : Pub
 
        PubE pubE = new PubE();
        pubE.FooEvent += Foo_FooEvent;                 // PubE event add
        pubE.Foo();                                    // Program+PubE sent a message : Pub
 
        PubFoo pubFoo = new PubFoo();
        pubFoo.FooEvent += Foo_FooEvent;
        pubFoo.Foo();                                  // Program+PubFoo sent a message : PubFoo
    }
}

5. 참조 자료