【问题标题】:Exception handling in delegate委托中的异常处理
【发布时间】:2013-07-10 14:34:15
【问题描述】:

我有以下代码,当它试图抛出错误时,它给了我一个“用户代码未处理异常”:

private static void _msgQ_RecieveCompleted(object sender, ReceiveCompletedEventArgs e)
{
    try
    {
        //queue that have received a message
        MessageQueue _mq = (MessageQueue)sender;

        //get the message off the queue
        Message _mqmsg = _mq.EndReceive(e.AsyncResult);
        throw new Exception("This is a test exception by Tim");

        //set the values back into a formatted struct 
        //now process your SQL....
        Azure_SQL _azuresql = new Azure_SQL();
        _azuresql.writeMessageToStorage((_TwitterStreamFeed)_mqmsg.Body);

        //refresh queue just in case any changes occurred (optional)
        _mq.Refresh();

        //tell MessageQueue to receive next message when it arrives
        _mq.BeginReceive();

        return;
    }
    catch 
    {
        throw;
    }
}

通过以下方法调用(以前是sn-p):

public void MSMQ_GetMessage(string _MQ_Path)
        {
            try
            {

                //set the correct message queue
                MessageQueue _msgQ = new MessageQueue(_MQ_Path, QueueAccessMode.ReceiveAndAdmin);
                //set the format of the message queue
                _msgQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(_TwitterStreamFeed) });
                try
                {
                    _msgQ.ReceiveCompleted += new ReceiveCompletedEventHandler(_msgQ_RecieveCompleted);
                }
                catch
                {
                    throw;
                }

                IAsyncResult _result = _msgQ.BeginReceive();
                _asyncList.Add(_result); // asyncList is a global variable of type System.Collections - > this allows the callback to remain open and therefore nit garbage collected while the async thread runs off on it's own
            }
            catch (Exception _ex)
            {
                throw new Exception("_msgQ_get Message threw the following error :- " + _ex);
            }
            catch
            {
                throw;
            }

        }

您能帮我理解为什么错误没有返回到ReceiveCompletedEventHandler 调用吗?我知道它在不同的线程上执行代码,但我从 MSDN 示例中不明白如何捕获异常。我期待异常返回到调用 try/catch 块。

【问题讨论】:

  • 你是重新抛出异常,而不是处理它?
  • 抱歉,但在您的代码截图中,您只是为您的事件订阅了一个处理程序。你不喜欢它。第二个 try/catch 块没有任何意义(除非您有自定义的事件添加/删除处理程序)。
  • 您试图在错误的位置捕获异常。异常不会在您将处理程序注册到事件的行中引发,而是在该事件被触发(调用)的行中引发。上面的代码中没有显示这一行。
  • 另外,所有这些catch { throw; } 位都没有任何作用,也没有做任何事情,应该被删除。
  • 我猜有一个对应的EndReceive,里面也有EndInvoke。在异步调用中,您会捕获 EndInvoke 中的异常,而不是 BeginInvoke

标签: c# exception-handling delegates try-catch msmq


【解决方案1】:

这里有四种方法。

在方法“A”中,异常对所有订阅者进行多播。这是通过将 Exception 实例作为“innerException”字段包含在您的自定义 EventArgs 类中来完成的。

在方法“B”中,异常通过调用单独的委托“带外”处理(不是多播,不是事件机制的一部分)。

在方法“C”中,您有一个应用程序级异常处理程序。 您想通知它此异常是作为处理 ReceiveCompleted 的一部分发生的。 通过定义(并抛出)一个 ReceiveCompletedException 来做到这一点,它有一个“innerException”字段来包含实际的异常。

在方法“D”(下面没有给出代码)中,您不关心异常发生在 ReceiveCompleted 代码中。您只需要一个通用的地方来处理异常。这称为“应用程序级异常处理”。见Catch-all error handling on application level?

方法 A:

// ========== A: multi-cast "innerException" integrated into EventArgs ==========

public class ReceiveCompletedEventArgs_A
{
    public string myData;   // Set on successful events (no exception).
    public Exception innerException;    // Set when there is an exception.
}

public delegate void ReceiveCompletedEventHandler_A(object sender, ReceiveCompletedEventArgs_A args);

// The Publisher of ReceiveCompleted event, with "innerException" mechanism.
public class RCPublisher_A
{
    public event ReceiveCompletedEventHandler_A ReceiveCompleted;

    public void OnRaiseReceiveCompletedEvent(string myData)
    {
        ReceiveCompletedEventArgs_A rc;
        try
        {
            rc = new ReceiveCompletedEventArgs_A { myData = myData };
            // Uncomment below line, to see an exception being handled.
            //throw new Exception("Testing exception handling");
        }
        catch (Exception ex)
        {
            rc = new ReceiveCompletedEventArgs_A { innerException = ex };
        }

        if (ReceiveCompleted != null)
            ReceiveCompleted(this, rc);
    }
}

// A Subscriber of ReceiveCompleted event, with "innerException" mechanism.
public class RCSubscriber_A
{
    public void Initialize(RCPublisher_A rcp)
    {
        rcp.ReceiveCompleted += OnReceiveCompleted;
    }

    private void OnReceiveCompleted(object sender, ReceiveCompletedEventArgs_A rc)
    {
        if (rc.innerException != null)
        {
            // Handle the exception
        }
        else
        {
            // Use rc.myData
        }
    }
}

方法 B:

// ========== B: "Out-of-band" handling of exceptions; not multi-cast ==========
// (Successful events are multi-cast, but exceptions are sent to a single delegate.)

public class ReceiveCompletedEventArgs_B
{
    public string myData;   // Set on successful events (no exception).
}

public delegate void ReceiveCompletedEventHandler_B(object sender, ReceiveCompletedEventArgs_B args);

public delegate void ExceptionDelegate(Exception ex);

// The Publisher of ReceiveCompleted event, with out-of-band Exception handling.
public class RCPublisher_B
{
    // Called when the event is successful (no exception).
    public event ReceiveCompletedEventHandler_B ReceiveCompleted;

    // Called when there is an exception.
    public ExceptionDelegate exceptionDeleg;

    public void OnRaiseReceiveCompletedEvent(string myData)
    {
        try
        {
            ReceiveCompletedEventArgs_B rc = new ReceiveCompletedEventArgs_B { myData = myData };
            // Uncomment below line, to see an exception being handled.
            //throw new Exception("Testing exception handling");

            if (ReceiveCompleted != null)
                ReceiveCompleted(this, rc);
        }
        catch (Exception ex)
        {
            if (exceptionDeleg != null)
                exceptionDeleg(ex);
            // What to do if there is no exceptionDeleg:
            //   If below line is commented out, unhandled exceptions are swallowed.
            //   Uncomment, to throw them to your app-level exception handler.
            else throw;
        }

    }
}

// A Subscriber of ReceiveCompleted event, with out-of-band Exception handling.
public class RCSubscriber_B
{
    public void Initialize(RCPublisher_B rcp)
    {
        rcp.ReceiveCompleted += OnReceiveCompleted;
        // CAUTION: Overrides any other exception delegate.
        // If you need multi-casting of the exception, see Approach A.
        rcp.exceptionDeleg = RCExceptionOccurred;
    }

    private void OnReceiveCompleted(object sender, ReceiveCompletedEventArgs_B rc)
    {
        // Use rc.myData
    }

    private void RCExceptionOccurred(Exception ex)
    {
        // Use ex.
    }
}

方法 C:

// ========== C: Wrap "innerException" into custom Exception, for app-level handler ==========
// Similar to B, but instead of adding ExceptionDelegate and exceptionDeleg,
// Define a custom exception type, and throw it.
// Catch it inside your app-level handler.
public class ReceiveCompletedException : Exception 
{
    public Exception innerException;
}

public class RCPublisher_C
{
    public event ReceiveCompletedEventHandler_B ReceiveCompleted;

    public void OnRaiseReceiveCompletedEvent(string myData)
    {
        ReceiveCompletedEventArgs_B rc;
        try
        {
            rc = new ReceiveCompletedEventArgs_B { myData = myData };
            // Uncomment below line, to see an exception being handled.
            //throw new Exception("Testing exception handling");

            if (ReceiveCompleted != null)
                ReceiveCompleted(this, rc);
        }
        catch (Exception ex)
        {
            throw new ReceiveCompletedException{ innerException =  ex };
        }
    }
}

// ...
// In your app-level handler:
        // ...
        catch (ReceiveCompletedException rce)
        {
           // If it gets here, then an exception happened in ReceiveCompleted code.
           // Perhaps you have some graceful way of restarting just that subsystem.
           // Or perhaps you want a more accurate log, that instead of just saying
           // "Exception XYZ happened" (the inner exception), logs that it was
           // ReceiveCompleted that has the problem.
           // use rce.innerException
        }
        // ...

【讨论】:

  • .. 以及在 catch 块中提出解决方案的人,然后在被否决后删除了他们的答案:我明白你想说什么。不要气馁。 (我不是反对你的人。)
  • 并查看@gustavo 的评论;关于 ReceiveCompleted,您可能还需要做更多事情,但是,这是一个单独的问题。你能多谈谈你希望发生的事情吗?
  • 感谢双方的响应...我想了解的是如何抛出委托方法 _msgQ_RecieveCompleted 中发生的异常。例如,我收到消息,然后调用 SQL 方法(引用的 dll)来写入数据。如果这引发异常,我想停止该过程并将某些内容打印到控制台应用程序说。我认为@Gustavo 的意思是,我需要对 ReceiveCompletedEventHandler 做“更多”来启用它。我想这就是我不明白的 - 对不起,代表和 MQ 的新手 -> 一直试图找到任何没有运气的例子..
  • Ridoy - 啊要清楚 - 异常没有被调用块(ReceiveCompletedEventHandler 块)捕获,它被委托类捕获,当它遇到“抛出”时,我得到未处理的异常我的代码中的错误..
  • @蒂姆。好的,我是倒着读的。我的书面回答无济于事——它在错误的地方你不能在你试图的地方“抛出”异常。您必须在 catch 块中捕获它,然后自己调用一些方法。这意味着您需要一个“回调挂钩”。创建处理程序时传递的函数参数。您将该函数引用存储在局部变量中,并在“catch”中调用它,将异常传递给它。不是我的答案中的“捕获” - 发生异常的那个。现在想出代码太累了。
猜你喜欢
  • 2018-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
相关资源
最近更新 更多