委托中的异常处理 [英] Exception handling in delegate

查看:181
本文介绍了委托中的异常处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码,它提供了一个异常被用户代码未处理,当它试图抛出一个错误:

  private static void _msgQ_RecieveCompleted(object sender,ReceiveCompletedEventArgs e)
{
try
{
//已收到消息的队列
MessageQueue _mq =(MessageQueue)sender;

//获取消息离开队列
消息_mqmsg = _mq.EndReceive(e.AsyncResult);
抛出新的异常(这是Tim的一个测试异常);

//将值设置为格式化的结构
//现在处理您的SQL ....
Azure_SQL _azuresql =新的Azure_SQL();
_azuresql.writeMessageToStorage((_ TwitterStreamFeed)_mqmsg.Body);

//刷新队列,以防发生任何更改(可选)
_mq.Refresh();

//告诉MessageQueue到达时收到下一条消息
_mq.BeginReceive();

return;
}
catch
{
throw;
}
}

通过以下方法调用(以前的代码段):

  public void MSMQ_GetMessage(string _MQ_Path)
{
try
{

//设置正确的消息队列
MessageQueue _msgQ = new MessageQueue(_MQ_Path,QueueAccessMode.ReceiveAndAdmin);
//设置消息队列的格式
_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是System.Collections类型的全局变量 - >这允许回调保持打开,因此在异步线程在自己的
$
catch(异常_ex)
{
抛出新的异常(_ msgQ_get消息引发以下错误: - + _ex);
}
catch
{
throw;
}

}

你能帮我理解为什么错误不会被转回到 ReceiveCompletedEventHandler 调用?我得到它正在不同的线程执行代码,但我不明白从 MSDN 示例如何捕获异常。我期待异常返回到调用 try / catch 块。

解决方案

四种方法。



在方法A中,异常是多播给所有订阅者。这是通过将Exception实例作为自定义EventArgs类中的innerException字段来实现的。



在方法B中,异常被处理为 />

在方法C中,您有一个应用程序级别的异常处理程序。
要通知它,这个异常发生在处理ReceiveCompleted的一部分。
通过定义(和抛出)一个ReceiveCompletedException来实现此操作,该接口具有一个innerException字段来包含实际的异常。



在方法D代码如下)你不在意,在ReceiveCompleted代码中发生异常。你只需要一个通用的地方来处理异常。这被称为应用程序级异常处理。请参阅应用程序级别的全部错误处理?



方法A:

  // ========== A:多重内容异常集成到EventArgs中========== 

public class ReceiveCompletedEventArgs_A
{
public string myData; //设置成功事件(无例外)。
public Exception innerException; //当有异常时设置
}

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

// ReceiveCompleted事件的发布者,带有innerException机制。
public class RCPublisher_A
{
public event ReceiveCompletedEventHandler_A ReceiveCompleted;

public void OnRaiseReceiveCompletedEvent(string myData)
{
ReceiveCompletedEventArgs_A rc;
try
{
rc = new ReceiveCompletedEventArgs_A {myData = myData};
//取消注释下面的行,查看正在处理的异常。
//抛出新的异常(测试异常处理);
}
catch(Exception ex)
{
rc = new ReceiveCompletedEventArgs_A {innerException = ex};
}

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

// ReceiveCompleted事件的订阅者,具有innerException机制。
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)
{
//处理异常
}
else
{
//使用rc.myData
}
}
}

方法B:

  // ========== B:Out-of-band处理异常;不是多播========== 
//(成功的事件是多播的,但是异常被发送到一个委托。)

public class ReceiveCompletedEventArgs_B
{
public string myData; //设置成功事件(无例外)。
}

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

public delegate void ExceptionDelegate(Exception ex);

//接收完成事件的发布者,带外异常处理。
public class RCPublisher_B
{
//当事件成功时调用(无例外)。
public event ReceiveCompletedEventHandler_B ReceiveCompleted;

//当有异常时调用。
public ExceptionDelegate exceptionDeleg;

public void OnRaiseReceiveCompletedEvent(string myData)
{
try
{
ReceiveCompletedEventArgs_B rc = new ReceiveCompletedEventArgs_B {myData = myData};
//取消注释下面的行,查看正在处理的异常。
//抛出新的异常(测试异常处理);

if(ReceiveCompleted!= null)
ReceiveCompleted(this,rc);
}
catch(Exception ex)
{
if(exceptionDeleg!= null)
exceptionDeleg(ex);
//如果没有异常,该如何处理:
//如果下面的行被注释掉,则会处理未处理的异常。
//取消注释,将其抛出到您的应用级异常处理程序中。
else throw;
}

}
}

//接收完成事件的用户,带外异常处理。
public class RCSubscriber_B
{
public void Initialize(RCPublisher_B rcp)
{
rcp.ReceiveCompleted + = OnReceiveCompleted;
//注意:覆盖任何其他异常委托。
//如果需要多次转换异常,请参阅方法A.
rcp.exceptionDeleg = RCExceptionOccurred;
}

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

private void RCExceptionOccurred(Exception ex)
{
//使用ex。
}
}

方法C:

  // ========== C:将innerException包装到自定义异常中,对于应用级处理程序======= === 
//与B类似,但不是添加ExceptionDelegate和exceptionDeleg,而是
//定义一个自定义异常类型,并将其抛出。
//在你的应用程序级处理程序中抓住它。
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};
//取消注释下面的行,查看正在处理的异常。
//抛出新的异常(测试异常处理);

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

// ...
//在你的应用级处理程序中:
// ...
catch(ReceiveCompletedException rce)
{
//如果它在这里,则ReceiveCompleted代码中发生异常。
//也许你有一些优雅的方式重新启动该子系统。
//或者你想要一个更准确的日志,而不是只说
//异常XYZ发生(内部异常),记录它是
// ReceiveCompleted问题。
//使用rce.innerException
}
// ...


I have the following code which gives me an "Exception was unhandled by user code" when it tries to throw an error:

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

It is called by the following method (previously the snippet):

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

        }

Can you help me understand why the error isn't thrown back to the ReceiveCompletedEventHandler call? I get that it's executing the code on a different thread, but I don't understand from the MSDN examples how to capture the exception. I was expecting the Exception to be return to the call try/catch block.

解决方案

Here are four approaches.

In approach "A", the Exception is multi-cast to all subscribers. This is done by including the Exception instance as an "innerException" field in your custom EventArgs class.

In approach "B", the Exception is handled "out-of-band" (not multi-cast, not part of the event mechanism) by calling a separate delegate.

In approach "C", you have an application-level exception handler. You want to inform it that this exception happened as part of processing ReceiveCompleted. Do this by defining (and throwing) a ReceiveCompletedException, which has an "innerException" field to contain the actual exception.

In approach "D" (no code given below) you don't care that the exception happened in ReceiveCompleted code. You just need a generic place to handle exceptions. This is known as "application-level exception handling". See Catch-all error handling on application level?

Approach 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
        }
    }
}

Approach 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.
    }
}

Approach 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
        }
        // ...

这篇关于委托中的异常处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆