【问题标题】:C#: Raising an inherited eventC#:引发继承的事件
【发布时间】:2010-10-19 20:46:57
【问题描述】:

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

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') 的左侧

我假设我无法像其他继承成员一样访问这些事件?

【问题讨论】:

标签: c# events inheritance


【解决方案1】:

我假设我无法像其他继承成员一样访问这些事件?

没错。通常为基类中的每个事件提供一个受保护的函数OnXyzRaiseXyz 以启用从继承的类中引发。例如:

public event EventHandler Loading;

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

在继承类中调用:

OnLoading();

【讨论】:

    【解决方案2】:

    你要做的,是这样的:

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

    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);
        }
    }
    

    【讨论】:

    • 除非有其他理由,否则这些方法应该受到虚拟保护。
    • 为什么应该是虚拟的?如果我想让继承者改变事件的引发方式,我会声明它是虚拟的,但大多数时候,我认为没有理由这样做......
    • 关于使方法虚拟化,以便继承者可以覆盖事件调用行为:您有多少次处于需要这样做的情况?旁边;在被覆盖的方法中,你不能引发事件,因为你会得到与 TS 提到的相同的错误。
    • @Verax 我遵循它是因为推理是合理的,这取决于我期望代码的可重用性和可扩展性,我提供了官方指南来支持它.. 在写你的时候对 .NET Verax 来说似乎也很新,所以你挖出来不同意我 7 年的经验有点令人困惑
    【解决方案3】:

    您只能访问声明类中的事件,因为 .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);
    

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

    约定是在声明类中提供类似的东西..

    protected virtual void OnMyPropertyChanged(EventArgs e)
    {
        EventHandler invoker = MyPropertyChanged;
    
        if(invoker != null) invoker(this, e);
    }
    

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

    【讨论】:

    • 我在实现这个时遇到了一些问题...stackoverflow.com/q/10593632/328397
    • 我更喜欢这个答案,因为它解释了为什么您必须使用该方法而不仅仅是该方法。干得好。
    【解决方案4】:

    你可以试试这个方法,对我有用:

    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);
        }
    }
    

    【讨论】:

    【解决方案5】:

    不要复活旧线程,但如果有人在看,我所做的是

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

    这使您可以在派生类中继承事件,这样您就可以在无需包装方法的情况下调用它,同时保持 += 语法。我想如果你这样做了,你仍然可以使用包装方法来做到这一点

    public event EventHandler MyPropertyChanged
    {
       add { AddDelegate(value); }
       remove { RemoveDelegate(value); }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-05
      • 2015-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-08
      • 1970-01-01
      相关资源
      最近更新 更多