从基类调用事件

本文关键字:事件 调用 基类 | 更新日期: 2023-09-27 18:06:01

我有以下场景:

public abstract class SomeBaseClass
{
    public event EventHandler SomeEvent;
    ...
}
public class SomeClass : SomeBaseClass
{
    public void DoSomething()
    {
        //TODO
        if (SomeEvent != null)
            SomeEvent(this, EventArgs.Empty);
    }
}

SomeBaseClass有一个需要在基类中调用的事件,但是这是不可能直接从基类调用事件的。为了解决这个问题,我可以在基类中重写事件,如下所示:

public class SomeClass : SomeBaseClass
{
    new public event EventHandler SomeEvent;

我想这很好,但是我的问题是是否有某种通用方法,或者良好实践实现上述功能?

不可能从基类调用事件的事实表明,我不应该首先这样做,也许调用事件的责任应该只在SomeBaseClass中?

从基类调用事件

这是不允许的。如果我可以推荐另一种方法:

public abstract class SomeBaseClass
{
    public event EventHandler SomeEvent;
    protected void RaiseSomeEvent(EventArgs e)
    {
        var eh = SomeEvent;
        if (eh != null)
            eh(this, e);
    }
}
public class SomeClass : SomeBaseClass
{
    public void DoSomething()
    {
        //TODO
        RaiseSomeEvent(EventArgs.Empty);
    }
}
请注意,我已经将事件处理程序的调用移动到所属类,这是. net/c#所要求的,因为只有该类才能调用事件处理程序。其次,我通过首先将事件处理程序分配给eh使其线程安全。

永远不要使用new关键字隐藏基类的事件!当您使用基类的类型作为变量的类型或基类调用事件时,您将得到意想不到的结果。

我会避免使用new,主要是因为如果对象被强制转换为基类,代码的行为会有所不同。下面是另一种实现:

public abstract class SomeBaseClass
{
    public virtual event EventHandler SomeEvent;
    protected virtual void HandleSomeEvent()
    {
        var ev = SomeEvent; // Localize event field used
        if (ev != null)
        {
            ev(this, EventArgs.Empty);
        }
    }
}
public class SomeClass : SomeBaseClass
{
    public override event EventHandler SomeEvent
    {
        add { base.SomeEvent += value; }
        remove { base.SomeEvent -= value; }
    }
    protected override void HandleSomeEvent()
    {
        base.HandleSomeEvent();
        // ... My own code here
    }
}

这允许很大的灵活性。您可以提供一些事件处理的实现,并允许实现者完全覆盖基类实现。

public delegate void ErrorHandler(string result);
public class BaseClass
{
   public event ErrorHandler OnError;
   protected void RaiseErrorEvent(string result)
   {
     OnError?.Invoke(result);
   }
 }
public class SampleClass:BaseClass
{
   public void Error(string s)
   {
     base.RaiseErrorEvent(s);
   }
}

我个人更喜欢使用委托:

   public abstract class SomeBaseClass
    {
        public event EventHandler SomeEvent;
        protected Action<object, EventArgs> SomeEventInvoker;
        public SomeBaseClass()
        {
            SomeEventInvoker = new Action<object, EventArgs>((sender, args) => 
             { if (SomeEvent != null) SomeEvent(sender, args); });
        }
    }
   public class SomeClass : SomeBaseClass
    {
        public SomeClass()
        {
            DoSomething();
        }
        public void DoSomething()
        {                
            SomeEventInvoker(this, new EventArgs());
        }
    }