C # : 상속 된 이벤트 발생


144

다음과 같은 이벤트가 포함 된 기본 클래스가 있습니다.

public event EventHandler Loading;
public event EventHandler Finished;

이 기본 클래스에서 상속받은 클래스에서 이벤트를 발생시킵니다.

this.Loading(this, new EventHandler()); // All we care about is which object is loading.

다음과 같은 오류가 발생합니다.

'BaseClass.Loading'이벤트는 + = 또는-= (BaseClass ')의 왼쪽에만 표시 될 수 있습니다.

상속받은 다른 회원과 동일한 이벤트에 액세스 할 수 없다고 가정합니다.


이 질문은 이미 Frederik Gheysels 에 의해 답변되었습니다 . Microsoft Docs에서도 동일한 방법이 권장됩니다. 파생 클래스에서 기본 클래스 이벤트를 발생시키는 방법 (C # 프로그래밍 가이드) 공식 "C # 프로그래밍 가이드"
Eliahu Aaron

답변:


160

당신이해야 할 일은 이것입니다 :

이벤트를 선언 한 기본 클래스에서 이벤트를 발생시키는 데 사용할 수있는 보호 된 메소드를 작성하십시오.

public class MyClass
{
   public event EventHandler Loading;
   public event EventHandler Finished;

   protected virtual void OnLoading(EventArgs e)
   {
       EventHandler handler = Loading;
       if( handler != null )
       {
           handler(this, e);
       }
   }

   protected virtual void OnFinished(EventArgs e)
   {
       EventHandler handler = Finished;
       if( handler != null )
       {
           handler(this, e);
       }
   }
}

이벤트 핸들러를 호출해야하는지 여부를 확인하려면 해당 메소드를 변경해야합니다.

그런 다음이 기본 클래스에서 상속 된 클래스에서 OnFinished 또는 OnLoading 메소드를 호출하여 이벤트를 발생시킬 수 있습니다.

public AnotherClass : MyClass
{
    public void DoSomeStuff()
    {
        ...
        OnLoading(EventArgs.Empty);
        ...
        OnFinished(EventArgs.Empty);
    }
}

5
다른 방법이없는 한 이러한 방법은 가상으로 보호해야합니다.
Max Schmeling

6
왜 가상이어야합니까? 상속자가 이벤트를 제기하는 방식을 변경하도록하려면 가상으로 선언하지만 대부분의 경우이 작업을 수행 할 이유가 없습니다 ...
Frederik Gheysels


5
메소드를 가상으로 만드는 것과 관련하여 상속자가 이벤트 호출 동작을 대체 할 수 있습니다. 이것이 필요한 상황에 몇 번이나 있었습니까? 그 옆에; 재정의 된 메서드에서는 TS에서 언급 한 오류와 동일한 오류가 발생하므로 이벤트를 발생시킬 수 없습니다.
Frederik Gheysels

2
@Verax 코드가 얼마나 재사용 가능하고 확장 가능한지에 따라 추론이 건전하기 때문에 그것을 따릅니다. 나는 그것을 백업하기위한 공식 지침을 제공했습니다. 7 년간의 경험에 동의하지
않기 위해 이것을 파헤치는

123

.NET은 실제로 델리게이트를 보유하는 씬 뒤에 프라이빗 인스턴스 변수를 생성하므로 선언 클래스의 이벤트에만 액세스 할 수 있습니다. 이거 ..

public event EventHandler MyPropertyChanged;

실제로이 작업을 수행하고 있습니다.

private EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

그리고 이걸 ...

MyPropertyChanged(this, EventArgs.Empty);

실제로 이것은 ...

myPropertyChangedDelegate(this, EventArgs.Empty);

따라서 선언 클래스 내에서만 private 대리자 인스턴스 변수에만 액세스 할 수 있습니다.

컨벤션은 선언 클래스에서 이와 같은 것을 제공하는 것입니다.

protected virtual void OnMyPropertyChanged(EventArgs e)
{
    EventHandler invoker = MyPropertyChanged;

    if(invoker != null) invoker(this, e);
}

그런 다음 OnMyPropertyChanged(EventArgs.Empty)해당 클래스의 어느 곳에서나 상속 계층 아래에서 호출하여 이벤트를 호출 할 수 있습니다.


나는이 ... 구현하는 몇 가지 문제가 있었다 stackoverflow.com/q/10593632/328397
goodguys_activate을

접근 방식 대신 접근 방식을 사용해야하는 이유를 설명하기 때문에이 대답을 선호합니다. 잘 하셨어요.
cowboydan

8

상속받은 다른 회원과 동일한 이벤트에 액세스 할 수 없다고 가정합니다.

정확하게. 상속 된 클래스에서 발생시킬 수 있도록 보호 된 기능을 제공 OnXyz하거나 RaiseXyz기본 클래스의 각 이벤트에 대해 관례 입니다. 예를 들면 다음과 같습니다.

public event EventHandler Loading;

protected virtual void OnLoading() {
    EventHandler handler = Loading;
    if (handler != null)
        handler(this, EventArgs.Empty);
}

상속 된 클래스에서 호출됩니다.

OnLoading();

0

이 방법으로 시도해 볼 수 있습니다.

public delegate void MyEventHaldler(object sender, EventArgs e);

public class B
{
    public virtual event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

public class D : B
{
    public override event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

2
이 문서에서는 컴파일러가 올바르게 처리하지 못한다고 주장하는 가상 이벤트 선언 및 재정의에 대해 경고합니다. msdn.microsoft.com/en-us/library/hy3sefw3.aspx
public wireless

0

오래된 실을 되 살릴 수는 없지만 누군가 가보고있는 경우, 내가 한 일은

protected EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

이렇게하면 파생 클래스에서 이벤트를 상속 할 수 있으므로 + = 구문을 유지하면서 메서드를 래핑하지 않고도 호출 할 수 있습니다. 그래도 랩핑 방법으로 그렇게 할 수 있다고 생각합니다.

public event EventHandler MyPropertyChanged
{
   add { AddDelegate(value); }
   remove { RemoveDelegate(value); }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.