C# 创建、测试和提交公共事件';事件处理程序中的,以防止订阅服务器中出现异常

C# 创建、测试和提交公共事件';事件处理程序中的,以防止订阅服务器中出现异常,c#,event-handling,C#,Event Handling,我看到很多代码只是这样调用eventhandler: if( OnyMyEvent != null) OnMyEvent(this,"args"); 但在这篇关于的文章中,他描述了一种引发事件的方法,这样异常订阅者就不会影响引发者。我很好奇这是否是一个应该应用的最佳实践 以下是一个示例(未经测试/编译),因此读者可以了解: public delegate void MessageReceivedEventHandler(object sender, MessageEventArgs e

我看到很多代码只是这样调用eventhandler:

if( OnyMyEvent != null)
    OnMyEvent(this,"args");
但在这篇关于的文章中,他描述了一种引发事件的方法,这样异常订阅者就不会影响引发者。我很好奇这是否是一个应该应用的最佳实践

以下是一个示例(未经测试/编译),因此读者可以了解:

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 ) );
        }
    }
}

这不是一个最佳实践,你到底为什么要隐藏一个例外? 如果这是您不信任的代码的异常,则不应直接从受信任的代码调用(事件或非事件)

如果异常仅在发行版中引发,而不是在调试中引发,该怎么办?如果仅在某些计算机上根据某些神秘设置引发异常,该怎么办?您将很难找到bug

必须避免捕获(异常)。请快点失败

在事件参数中设置错误更具表现力,订阅者将知道如何通知您错误:

public class MyEventArgs : EventArgs
{
  private List<MyException> errors = new List<MyException>();

  public ICollection<MyException> Errors { get { return errors; } }
}
公共类MyEventArgs:EventArgs
{
私有列表错误=新列表();
公共ICollection错误{get{return Errors;}}
}

这不是最佳实践,你到底为什么要隐藏一个异常? 如果这是您不信任的代码的异常,则不应直接从受信任的代码调用(事件或非事件)

如果异常仅在发行版中引发,而不是在调试中引发,该怎么办?如果仅在某些计算机上根据某些神秘设置引发异常,该怎么办?您将很难找到bug

必须避免捕获(异常)。请快点失败

在事件参数中设置错误更具表现力,订阅者将知道如何通知您错误:

public class MyEventArgs : EventArgs
{
  private List<MyException> errors = new List<MyException>();

  public ICollection<MyException> Errors { get { return errors; } }
}
公共类MyEventArgs:EventArgs
{
私有列表错误=新列表();
公共ICollection错误{get{return Errors;}}
}

防止订阅者抛出异常的方法是处理异常。除了log和rethrow(这与其说是处理异常,不如说是让它在处理过程中做一个简单的迂回),有两种异常处理:智能和愚蠢

智能异常处理是指当您知道某个给定方法可以抛出什么类型的异常时,您了解可能导致这种情况发生的情况,并且您知道从中恢复的正确方法

愚蠢的异常处理就是一切。如果你不知道为什么一个方法会抛出一个异常,你就不知道处理这个异常是安全的

对于具有六个订阅服务器的事件处理程序,如果第一个订阅服务器抛出异常,您如何知道调用其他五个订阅服务器是安全的?你没有。你有个例外。您已经完成了,直到您发现异常的原因并修复它。如果调用其他事件处理程序,您所能期望的最好结果就是导致异常的条件不会导致它们发生故障

在某些情况下这是不正确的,但一般来说,如果这些情况适用,您就可以进行智能异常处理。例如,如果订阅事件处理程序的东西正在向外部系统发送异常,您可能会说“如果其中一个失败,我仍然应该发送所有其他消息。”但您之所以知道这一点,是因为您了解事件及其处理程序协作解决的特定问题空间


但这是默认的吗?这与最佳实践正好相反。

防止订阅者抛出异常的方法是处理异常。除了log和rethrow(这与其说是处理异常,不如说是让它在处理过程中做一个简单的迂回),有两种异常处理:智能和愚蠢

智能异常处理是指当您知道某个给定方法可以抛出什么类型的异常时,您了解可能导致这种情况发生的情况,并且您知道从中恢复的正确方法

愚蠢的异常处理就是一切。如果你不知道为什么一个方法会抛出一个异常,你就不知道处理这个异常是安全的

对于具有六个订阅服务器的事件处理程序,如果第一个订阅服务器抛出异常,您如何知道调用其他五个订阅服务器是安全的?你没有。你有个例外。您已经完成了,直到您发现异常的原因并修复它。如果调用其他事件处理程序,您所能期望的最好结果就是导致异常的条件不会导致它们发生故障

在某些情况下这是不正确的,但一般来说,如果这些情况适用,您就可以进行智能异常处理。例如,如果订阅事件处理程序的东西正在向外部系统发送异常,您可能会说“如果其中一个失败,我仍然应该发送所有其他消息。”但您之所以知道这一点,是因为您了解事件及其处理程序协作解决的特定问题空间


但这是默认的吗?这与最佳实践正好相反。

首先,我同意。要澄清的是,问题可能是:为了允许所有订阅者获得事件,或者让前2个订阅者获得事件,第3个订阅者抛出,其余6个订阅者永远不会得到通知。即使有一个或多个订阅者抛出,也要求通知所有订阅者是否是最佳做法。您可以通过特定的例外情况来做到这一点,但我强烈建议您在EventArgs中设置错误并避免这种奇怪的事件调用。首先,我同意。要澄清的是,问题可能是:为了允许所有订阅者获得事件,或者让前2个订阅者获得事件,第3个订阅者抛出,其余6个订阅者永远不会得到通知。即使一个或多个订阅者收到通知,要求通知所有订阅者是否是最佳做法