在正常代码流中使用异常
本文关键字:异常 代码 常代码 | 更新日期: 2023-09-27 18:13:13
我知道不应该在非异常条件下使用异常,但是我想让其他人看看我想做的事情是否真的那么糟糕。
我有一个例程,它试图从MSMQ消息队列中获取消息。如果队列上没有可用的消息,它将检查辅助源,以查看那里是否有可用的消息。例程示例如下:
void CheckForMessages(out Message msg, TimeSpan timeout)
{
try
{
queue.Peek(timeout);
}
catch(MessageQueueException ex)
{
if (e.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
{
if (messageAvailable)
{
msg = SecondaryMessageSource();
}
}
throw;
}
msg = queue.Receive();
}
MSMQ不提供检查队列上消息计数的机制。确定消息是否可用的唯一方法是使用Peek。如果发生MessageQueueException,其错误设置为IOTimeout,则Peek已经超时,队列中没有可用的消息。
这个例程将在线程的循环中调用,该线程的唯一目的是检索消息。超时时间将在毫秒范围内。调用堆栈由一个方法组成,线程不负责做任何其他事情。我知道这个方法会不断抛出异常,这被认为是不好的做法,但在这种情况下,它真的那么糟糕吗?如果是这样,谁有什么建议,如何完成这个任务,而不使代码变得完全复杂?
由于您的程序逻辑(检查一个队列,如果没有消息,检查另一个队列)和MSMQ的工作方式,您将不得不处理异常。但是,我觉得可能有一种比在catch子句中使用这些代码更优雅的方法。
我会这样做:
private const int ReceiveTimeout = xxxx;
private bool TryReceiveMessage(MessageQueue queue, out Message message)
{
try
{
message = queue.Receive(ReceiveTimeout);
// if we made it here, we are good and have a message
return true;
}
catch(MessageQueueException ex)
{
if (MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
{
// this is not exceptional to us, so just return false
return false;
}
// Throw anything else as it is unexpected
throw;
}
}
然后,我将您的调用方法编码为:
private Message MyMethodThatIsCalledInALoop()
{
// These could also be params, etc.
MessageQueue primary = // whatever code to get a reference to your primary queue
MessageQueue secondary = // whatever code to get a reference to your secondary queue
Message message = null;
if (TryReceiveMessage(primary, out message))
{
return message;
}
if (TryReceiveMessage(secondary, out message))
{
return message;
}
// this would still be null
return message;
}
MSMQ不提供检查队列上消息计数的机制。确定消息是否可用的唯一方法是使用Peek。如果发生MessageQueueException,其错误设置为IOTimeout,则Peek已经超时,队列上没有可用的消息
你自己回答的。既然没有别的办法,你还有什么选择呢?
应该为每个轮询作业创建2个单独的线程,并让它们将消息存储在同步队列中,以便主线程可以对它们进行排序并从中获取适当的消息。这样,您就可以在Peek
调用上设置"无限"超时。