MessageQueue不止一次处理

Bob*_*orn 5 c# dispose message-queue

我在其他帖子上看到过这个错误,但不是这个确切的情况.

我有两个类使用MessageQueue执行相同的操作.因此,我将队列的创建和处理抽象为helper类.我收到此错误,我无法看到队列如何被多次处理.

对象'messageQueue'可以在方法'MsmqHelper.DisposeQueue(MessageQueue)'中多次处理

在其中一个类中,这是队列的使用方式:

private MessageQueue _messageQueue;
Run Code Online (Sandbox Code Playgroud)

然后,在类的构造函数中:

this._messageQueue = MsmqHelper.InitializeQueue();
Run Code Online (Sandbox Code Playgroud)

这并不重要,但为了完整性,这里是使用队列的地方:

this._messageQueue.Send(workflowCreated);
Run Code Online (Sandbox Code Playgroud)

以下是Dispose方法:

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
    if (disposing == false) { return; }

    MsmqHelper.DisposeQueue(this._messageQueue);
}
Run Code Online (Sandbox Code Playgroud)

这是helper类中实际调用Dispose()的代码:

public static void DisposeQueue(MessageQueue messageQueue)
{
    if (messageQueue != null)
    {
        messageQueue.Close();
        messageQueue.Dispose();
        messageQueue = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,队列可以在哪里被处置多次?

**编辑**

我认为在下面的对话中添加我的评论会很高兴.这是一个很好的总结,以及接受的答案:

我想我现在明白了.messageQueue方法参数与对象的原始(this._messageQueue)引用无关.因此,检查messageQueue为null,并将其设置为null,没有用.即使在被处理之后,调用者仍然可以传入其变量(this._messageQueue).因此,能够不止一次地处置.

顺便说一句,即使在调用方法中将调用者的变量(this._messageQueue)设置为null也无济于事.该问题仅存在于MsmqHelper.DisposeQueue()中.所以答案是通过ref传递或者根本不调用DisposeQueue()并在调用方法中完成所有操作.

**编辑2**

尝试这个后,我得到了同样的错误.我根本就没有得到它.

public static void DisposeQueue(ref MessageQueue messageQueue)
{
    if (messageQueue == null) { return; }

    messageQueue.Close();
    messageQueue.Dispose();
    messageQueue = null;
}
Run Code Online (Sandbox Code Playgroud)

**编辑3 - Bug?**

我开始认为这可能是一个错误.如果我评论messageQueue.Dispose(),则错误消失.但是,我可以调用方法中一起调用messageQueue.Close()和messageQueue.Dispose().去搞清楚.我想我只是从调用方法进行相同的调用,或者只调用Close()或Dispose()而不是两者.

Jim*_*Jim 2

关闭会释放 MessageQueue 对象的所有资源。请参阅此处的文档。该错误很可能是在 CA 中生成的,因为它发现 Close 的执行路径也调用了 Dispose。

从文档中:

    public  void ReceiveMessage()
    {
        // Connect to the a on the local computer.
        MessageQueue myQueue = new MessageQueue(".\\myQueue");

        // Set the formatter to indicate body contains an Order.
        myQueue.Formatter = new XmlMessageFormatter(new Type[]
            {typeof(String)});

        try
        {
            // Receive and format the message. 
            Message myMessage1 = myQueue.Receive();
            Message myMessage2 = myQueue.Receive();
        }

        catch (MessageQueueException)
        {
            // Handle sources of any MessageQueueException.
        }

        // Catch other exceptions as necessary.

        finally
        {
            // Free resources.
            myQueue.Close();
        }

        return;
    }
Run Code Online (Sandbox Code Playgroud)

关闭显然会释放资源,但如果尚未收集资源,则允许组件重新获取它们。打开 MessageQueue 对象、使用它,然后在同一调用中关闭它可能比打开一段时间然后稍后关闭它更为谨慎,因为连接缓存消除了在重复调用中打开 MessageQueue 的开销。

*更新* 看来,CA 对成员字段的 CA2202 处理方式与将一次性对象传递给方法不同,即使该方法对于类来说是私有的。无论如何,根据文档,您应该只需要调用 Close() 或 Dispose(),而不是同时调用两者。不过,我建议更改您的设计,以便您在消息操作范围内创建、使用然后关闭 MessageQueue 对象,如上面文档示例中的示例所示。