在正常代码流中使用异常

时间:2013-05-13 11:23:44

标签: c# exception

我知道你不应该在非特殊情况下使用例外,但是我想要通过其他人来看看我想做的事情是不是真的那么糟糕。

我有一个试图从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已超时且队列中没有可用消息。

此例程将在线程的循环内调用,该线程的唯一目的是检索消息。超时将在毫秒范围内。调用堆栈由单个方法组成,并且线程负责不执行任何其他操作。我知道该方法将不断抛出异常,这被认为是不好的做法,但在这种情况下它真的那么糟糕吗?如果是这样,是否有人对如何完成此任务有任何建议,而代码不会完全错综复杂?

3 个答案:

答案 0 :(得分:2)

由于你的程序逻辑(检查一个队列,如果没有消息,检查另一个),并且由于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;
}

答案 1 :(得分:0)

  

MSMQ没有提供检查队列中消息计数的机制。确定消息是否可用的唯一方法是使用Peek。如果发生MessageQueueException并将其错误设置为IOTimeout,则Peek已超时并且队列中没有可用消息

你自己回答了。由于没有别的办法,你有什么选择?

答案 2 :(得分:0)

您应该为每个轮询作业创建2个单独的线程,并让它们将消息存储在同步队列中,以便主线程可以对它们进行排序并从中获取适当的线程。这样,您就可以在Peek来电中设置“无限”超时。