我有以下情况:
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
?
答案 0 :(得分:9)
确实不允许这样做。如果我可以推荐一种替代方法:
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
关键字进行活动!当您使用基类时,您将获得意想不到的结果。键入变量的类型或基类调用事件。
答案 1 :(得分:3)
我会远离使用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
}
}
这样可以提供很大的灵活性。您可以提供一些事件处理实现,并允许实现者完全覆盖基类实现。
答案 2 :(得分:0)
我个人更喜欢使用代表:
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());
}
}
答案 3 :(得分:0)
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);
}
}