我看到很多代码只是像这样调用事件处理程序:
if( OnyMyEvent != null)
OnMyEvent(this,"args");
但是在C# Event Implementation Fundamentals, Best Practices and Conventions By Jeffrey Schaefer: 7) Event Raising Code上的这篇文章CodeProject中,他描述了一种引发事件的方法,以便例外订阅者不会影响提升者。我很好奇这是否是应该应用的最佳实践。
这是一个示例(未经过测试/编译),因此读者可以理解:
public delegate void MessageReceivedEventHandler(object sender, MessageEventArgs e);
class MessageEventArgs : EventArgs
{
public string Message
{ get; set; }
public MessageEventArgs( string message )
{ this.Message = message; }
}
class EventTriggeringClass
{
public event MessageReceivedEventHandler MessageReceived;
protected virtual void OnMessageReceived( MessageEventArgs e )
{
this.RaiseTriggerOnMessageReceived( e );
}
private void RaiseOnMessageReceived( MessageEventArgs e )
{
MessageReceivedEventHandler handler = this.MessageReceived;
if ( handler != null )
{
Delegate[] eventHandlers = handler.GetInvocationList();
foreach ( Delegate currentHandler in eventHandlers )
{
MessageReceivedEventHandler currentSubscriber = ( currentHandler as MessageReceivedEventHandler );
try
{
currentSubscriber( this, e );
}
catch ( Exception ex )
{
Debug.Assert( ex == null, ex.Message, ex.ToString() );
}
}
}
}
public void Read()
{
bool foundMessage = false, hasMoreMessages = true;
string msg;
while( hasMoreMessages )
{
// this way or..
if( foundMessage )
this.OnMessageReceived( new MessageEventArgs( msg ) );
// the other way
if( MessageReceived != null )
MessageReceived(this, new MessageEventArgs( msg ) );
}
}
}
答案 0 :(得分:1)
防止订阅者抛出异常的方法是处理异常。排除log-and-rethrow(这不是处理异常,只是让它绕道而行),有两种异常处理:智能和愚蠢。
智能异常处理是指当您知道给定方法可以抛出什么类型的异常时,您了解可能导致该异常发生的情况,并且您知道从中恢复的正确方法是什么。
愚蠢的异常处理就是其他一切。如果您不知道为什么方法会抛出异常,您就无法知道处理异常是安全的。
如果事件处理程序有六个订阅者,如果第一个订阅者抛出异常,你怎么知道调用其他五个是安全的?你没有。你有一个例外。你完成了,直到你找到导致异常的原因并修复它。如果你调用其他事件处理程序,你可以期望的最好的是导致异常的条件不会导致它们发生故障。
在某些情况下,这是不正确的,但一般来说,如果这些情况适用,您就可以进行智能异常处理。例如,如果订阅事件处理程序的事情是向外部系统发送异常,您可能会说“如果其中一个失败,我仍然应该发送所有其他消息”。但您只知道,因为您了解事件及其处理程序正在协作解决的特定问题空间。
但是默认这样做?这与最佳做法完全相反。
答案 1 :(得分:0)
这不是最佳做法,为什么你会隐藏一个例外? 如果这是您不信任的代码的异常,则不应直接从可信代码调用此代码(事件与否)。
如果仅在发布中而不是在调试中引发异常,该怎么办?如果根据某些神秘设置仅在某些计算机上引发异常怎么办?您将很难找到错误。
必须避免catch(异常)。请快点失败!
在事件参数中设置错误更具表现力,订阅者将知道如何通知您错误:
public class MyEventArgs : EventArgs
{
private List<MyException> errors = new List<MyException>();
public ICollection<MyException> Errors { get { return errors; } }
}