【问题标题】:Using Exceptions in Normal Code Flow在正常代码流中使用异常
【发布时间】:2013-05-13 20:43:34
【问题描述】:

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

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

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

【问题讨论】:

  • 使用Peek 的替代方法是什么?

标签: c# exception


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 我认为这是一个 XY 问题。预期的解决方案只能以丑陋的方式实现,但真正的问题可能会有更多的解决方案。
    • 他说另一个队列是次要来源。即故障转移。
    • 好吧,如果这意味着第二个队列不得被读取,除非第一个队列失败,那么异常解决方案是唯一正确的解决方案。不过他没有明确说明。
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2010-11-08
      • 2015-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多