从基类调用事件
本文关键字:事件 调用 基类 | 更新日期: 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());
}
}