C#:提升继承的事件

jwa*_*ech 139 c# events inheritance

我有一个包含以下事件的基类:

public event EventHandler Loading;
public event EventHandler Finished;
Run Code Online (Sandbox Code Playgroud)

在继承自此基类的类中,我尝试引发事件:

this.Loading(this, new EventHandler()); // All we care about is which object is loading.
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

事件'BaseClass.Loading'只能出现在+ =或 - =(BaseClass')的左侧

我假设我不能像其他继承的成员一样访问这些事件?

Fre*_*els 149

你要做的是这样的:

在您的基类(您已声明事件的位置)中,创建可用于引发事件的受保护方法:

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);
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

(请注意,您应该更改这些方法,以便检查是否必须调用eventhandler).

然后,在从此基类继承的类中,您只需调用OnFinished或OnLoading方法来引发事件:

public AnotherClass : MyClass
{
    public void DoSomeStuff()
    {
        ...
        OnLoading(EventArgs.Empty);
        ...
        OnFinished(EventArgs.Empty);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么要虚拟?如果我希望继承者改变事件的引发方式,我会声明它是虚拟的,但大多数时候,我认为没有理由这样做...... (6认同)
  • 除非有其他原因,否则这些方法应该受到虚拟保护. (5认同)
  • 关于使方法成为虚拟,以便继承者可以覆盖事件调用行为:您有多少次处于必要的情况?接下来; 在overriden方法中,您不能引发事件,因为您将获得与TS提到的相同的错误. (5认同)
  • 官方指南:http://msdn.microsoft.com/en-us/library/w369ty8x(VS.80).aspx (4认同)
  • @Verax我遵循它是因为推理是合理的,取决于我期望代码的可重用性和可扩展性,我提供了官方指导来支持它...在撰写本文时,您对.NET Verax似乎也是新手所以你有点困惑,不同意我7年的经验 (2认同)

Ada*_*son 121

您只能访问声明类中的事件,因为.NET在实际持有委托的场景后面创建私有实例变量.这样做..

public event EventHandler MyPropertyChanged;
Run Code Online (Sandbox Code Playgroud)

实际上是这样做的;

private EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}
Run Code Online (Sandbox Code Playgroud)

这样做......

MyPropertyChanged(this, EventArgs.Empty);
Run Code Online (Sandbox Code Playgroud)

实际上是......

myPropertyChangedDelegate(this, EventArgs.Empty);
Run Code Online (Sandbox Code Playgroud)

因此,您(显然)只能从声明类中访问私有委托实例变量.

惯例是在声明类中提供类似的东西..

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

    if(invoker != null) invoker(this, e);
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以OnMyPropertyChanged(EventArgs.Empty)从该类中的任何位置或继承层下面调用该类事件来调用该事件.


Kon*_*lph 8

我假设我不能像其他继承的成员一样访问这些事件?

正是.习惯上提供受保护的函数OnXyzRaiseXyz基类中的每个事件以启用从继承的类中提升.例如:

public event EventHandler Loading;

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

在继承的类中调用:

OnLoading();
Run Code Online (Sandbox Code Playgroud)