【问题标题】:Raising event from base class从基类引发事件
【发布时间】:2010-10-03 09:06:52
【问题描述】:

我知道可以在发生实现声明的类中引发事件,但我希望在基类级别引发事件并引发派生类的事件:

public interface IFoo
{
    event EventHandler<FooEventArgs> FooValueChanged;
    void RaiseFooValueChanged(IFooView sender, FooEventArgs  e);
}

[TypeDescriptionProvider(typeof(FooBaseImplementor))]
public abstract class FooBase : Control, IFoo
{
    public virtual event EventHandler<FooEventArgs> FooValueChanged;

    public void RaiseFooValueChanged(IFooView sender, FooEventArgs e)
    {
        FooValueChanged(sender, e);
    }
}

我不能有 FooValueChanged 事件抽象,因为这样基类就不能引发事件。当前代码运行,但调用 FooValueChanged(sender, e) 抛出 NullReferenceException,因为它不调用派生类的事件,只调用基类的事件。

我哪里错了?

我可以将事件和引发者都抽象化,但是我需要记住在每个派生类中调用 FooValueChanged(sender, e)。我试图避免这种情况,同时能够将 Visual Studio 设计器用于派生控件。

【问题讨论】:

标签: c# .net winforms events inheritance


【解决方案1】:

最终结果:

public interface IFoo
{
    event EventHandler<FooEventArgs> FooValueChanged;
    void RaiseFooValueChanged(IFooView sender, FooEventArgs e);
}

[TypeDescriptionProvider(typeof(FooBaseImplementor))]
public abstract class FooBase : Control, IFoo
{
    protected event EventHandler<FooEventArgs> backEndStorage;
    public abstract event EventHandler<FooEventArgs> FooValueChanged;

    public void RaiseFooValueChanged(IFooView sender, FooEventArgs e)
    {
        if (backEndStorage != null)
            backEndStorage(sender, e);
    }
}

public class FooDerived : FooBase {
    public override event EventHandler<FooEventArgs> FooValueChanged {
        add { backEndStorage += value; }
        remove { backEndStorage -= value; }
    }
}

【讨论】:

    【解决方案2】:

    首先请注意,您使用的事件声明是 C# 中的简写符号:

    public event EventHandler Event;
    public void RaiseEvent() {
        this.Event(this, new EventArgs());
    }
    

    相当于:

    private EventHandler backEndStorage;
    public event EventHandler Event {
        add { this.backEndStorage += value; }
        remove { this.backEndStorage -= value; }
    }
    public void RaiseEvent() {
        this.backEndStorage(this, new EventArgs());
    }
    

    其中 backEndStorage 是多播委托。


    现在你可以重写你的代码了:

    public interface IFoo
    {
        event EventHandler<FooEventArgs> FooValueChanged;
        void RaiseFooValueChanged(IFooView sender, FooEventArgs  e);
    }
    
    [TypeDescriptionProvider(typeof(FooBaseImplementor))]
    public abstract class FooBase : Control, IFoo
    {
        protected event EventHandler<FooEventArgs> backEndStorage;
        public event EventHandler<FooEventArgs> FooValueChanged {
            add { this.backEndStorage += value; }
            remove { this.backEndStorage -= value; }
        }
    
        public void RaiseFooValueChanged(IFooView sender, FooEventArgs e)
        {
            this.backEndStorage(sender, e);
        }
    }
    
    public class FooDerived : FooBase {
        public event EventHandler<FooEventArgs> AnotherFooValueChanged {
            add { this.backEndStorage += value; }
            remove { this.backEndStorage -= value; }
        }
    }
    

    所以现在在派生类上添加事件时,它们实际上会被添加到基类的 backEndStorage 中,从而允许基类调用派生类中注册的委托。

    【讨论】:

    • 很好的答案,几乎正是我所追求的。我将发布使用您的建议的最终解决方案。谢谢。
    • 请注意,基于Hidden Features of C#,您可以:protected event EventHandler&lt;FooEventArgs&gt; backEndStorage = delegate {};,然后不检查是否为空。
    【解决方案3】:

    为什么需要使用事件?你不能只使用一个覆盖的方法。基类调用可重写方法,派生类“拦截”该方法,然后可以引发事件?

    【讨论】:

      猜你喜欢
      • 2010-10-21
      • 1970-01-01
      • 2015-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多