2012-03-20 8 views
5

このエラーは他の投稿では見られましたが、このような状況では発生しませんでした。MessageQueueが1回以上廃棄されました

私は、MessageQueueで同じことをする2つのクラスを持っています。そのため、私はキューの作成と処分をヘルパークラスに抽象化しました。私はこのエラーが発生している、と私はキューが複数回配置することができないのか分かりません。

オブジェクトは「メッセージキュー「MsmqHelper.DisposeQueue(メッセージキュー)」メソッドに複数回配置することができる

クラスのいずれかで、このキューを使用する方法である:

そして
private MessageQueue _messageQueue; 

、クラスのコンストラクタで:キューを使用する場合、それは本当に重要ないこと

this._messageQueue = MsmqHelper.InitializeQueue(); 

、完全を期すために、ここにある:

this._messageQueue.Send(workflowCreated); 

そしてここでは、処分の方法です:

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

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

    MsmqHelper.DisposeQueue(this._messageQueue); 
} 

そして、これは実際には()のDisposeを呼び出すヘルパークラスのコードです:キューのためにそれが可能である

public static void DisposeQueue(MessageQueue messageQueue) 
{ 
    if (messageQueue != null) 
    { 
     messageQueue.Close(); 
     messageQueue.Dispose(); 
     messageQueue = null; 
    } 
} 

この状況で2回以上処分されるのでしょうか?

**編集**

は、私はここで、以下の会話の中で、私のコメントを追加するにはいいだろうと思いました。それは受け入れられた答えと一緒に良い要約です:

私は今それを得ると思います。 messageQueueメソッドのパラメータは、オブジェクトへの元の参照(this._messageQueue)とは関係ありません。だから、nullのmessageQueueをチェックし、それをヌルに設定するといいことはありません。呼び出し側は、その変数(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; 
} 

**編集3 - バグ? **

これはバグかもしれないと思っています。私がmessageQueue.Dispose()をコメントすると、エラーは消え去ります。ただし、を呼び出してQQueue.Close()とmessageQueue.Dispose()を呼び出す方法は、メソッドを呼び出してください。 Go figure。私は、呼び出しメソッドからこれらの同じ呼び出しを行うか、または両方の代わりにClose()またはDispose()を呼び出すだけであると思います。

+0

ここで、 'public void Dispose()(bool disposing)'メソッドが定義されていますか? – Tigran

+0

'Close'と' Dispose'が同じことをする可能性がありますか? –

+0

@Lasseそれは興味深い考えです。私はClose()行にコメントし、コンパイルしました。それから、私はClose()行のコメントを外し、Dispose()行をコメントして、まだコンパイルしました。あなたが言ったことが答えかもしれません。私は前のコードで両方の行(Close()とDispose())を持っていたと誓っていました。私はちょうどチェックし、私はしました。今私は何を考えるべきか分からない。 –

答えて

2

閉じるメッセージキューオブジェクトのすべてのリソースを解放します:あなたは、単に

それを使用することができ、あなたのコードは次のように簡略化されるかもしれない、使い捨てのパターンを台無しにアップする必要はありません。 documentation hereを参照してください。このエラーは、Closeの実行パスもDisposeを呼び出すため、CAで生成される可能性が最も高いです。ドキュメントから

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

閉じるには、明らかにリソースを解放しますが、彼らはまだ収集されていない場合、コンポーネントは、それらを再取得することができます。 MessageQueueオブジェクトを開いて使用した後、同じ呼び出しで一定期間閉じてから閉じると、接続キャッシュによって繰り返し呼び出しでMessageQueueを開くオーバーヘッドがなくなるので、後で閉じることが重要です。

* UPDATE * CAがそのメソッドがクラスにプライベートであったとしても、メソッドに使い捨てのオブジェクトを渡す対メンバフィールドごとに異なるCA2202を扱うことが表示されます。それにかかわらず、ドキュメントによれば、Close()またはDispose()を呼び出すだけで、両方を呼び出す必要はありません。ただし、上記の例のようなメッセージ操作のスコープ内で、MessageQueueオブジェクトを作成、使用、閉じられるように設計を変更することをおすすめします。

+1

私はそれも考えましたが、そうではありません。上記の編集3を参照してください。 –

+0

両方を正常に呼び出すことはできますが、なぜCAが1つのケースで不具合を抱えているのですか。つまり、おそらくMessageQueueを開いて使用し、できるだけ早く閉じたり破棄したりするべきでしょう。シナリオでガベージコレクションの前にリソースを再取得する必要がある場合にのみ、closeを使用します。それ以外の場合は、接続キャッシュによって後続のMessageQueueオブジェクトを少しオーバーヘッドで再作成/開くことができます。ありがとう、ジム。 – Jim

+1

私はあなたの答えを受け入れています。これは状況を最もよく理解しているからです。「CAはCA2202をメンバフィールドと違う方法で取り扱いますが、ディスポーザブルオブジェクトはメソッドに渡します。 –

2

はい。これにより、オブジェクトを複数回処理できます。

this._messageQueueと評価される値は、MsmqHelper.DisposeQueue(this._messageQueue)を呼び出した後にではなく、と変化します。

のみローカルパラメータmessageQueueと命名)DisposeQueue方法で値nullを割り当てました。したがって、「ヌルガード」は、その後の時間を正確にガードすることができません。

refに取るか、呼び出し元にthis._messageQueue = nullを割り当てる次のいずれか(これは、 『オブジェクトへの参照の値を渡す』の文脈の中で意味を理解するためのリンクを参照してください。C#のデフォルトの動作がCall-By-Valueあるためです)。

+0

ああ、キューをnullに設定していないので、変数(オブジェクトへのポインタ)をnullに設定していました。そして私はDisposeQueue()メソッドのパラメータに対してそうしていました。これは、this._messageQueueがまだ参照を指していて、nullに設定されていないことを意味します。そうですか? –

+0

* * never *オブジェクトをヌルのみの変数に設定します;-) 'this._messageQueue'はまだ*以前と同じオブジェクトを評価します、はい。 –

+0

コンパイラは 'DisposeQueue'メソッドについて不平を言っていることに注意してください。このメソッドは、実際には1回だけオブジェクトを破棄することに注意してください(これは、クラスの型について話しているときに" Evaluates to " *は複数回呼び出されますが、複数回呼び出されるのではなく、メソッド自体についての苦情です。私は、同じことをしているにもかかわらず、警告が 'Close'と' Dispose'について呼び出されている可能性が高いと思います(オブジェクトの処分)。 –

1

メッセージキュークラスはIDisposable iterfaceを実装している場合、すべてのこのようなクラスにclose()メソッドは、通常iterface方法ではなく、クラスメソッドではありませんので、その後、Disposeメソッドを明示的およびclose()メソッドを使用するためにはポイントが存在しません。通常、Disposeメソッドでは、すべての正しい実装が、管理対象/非管理対象リソースを解放する前にClose()メソッドを呼び出す必要があります。

また、外部スタティックヘルパーをインプリメントすると、Disposableパターンが破損します。これは、オブジェクトのライフタイムを制御する正しい方法ではありません。

// 1. Use static class. By the agreement, all helper classes should be static to avoid 
    // IDisposable inheritance, in example 
    public static class MsmqHelper//: IDisposable 
    { 
     //private MessageQueue _messageQueue; 

     //public MessageQueueHelper(bool workflowCreated) 
     //{ 
     // this._messageQueue = MsmqHelper.InitializeQueue(); 
     // this._messageQueue.Send(workflowCreated); 
     //} 

     public static SendMessage(object workflowCreated) 
     { 
      // 2. If static method in static class does not takes parameters, 
      // I might be better to to implicitly call the constructor? 

      // using(MessageQueue msmsq = MsmqHelper.InitializeQueue()) 

      using(MessageQueue msmsq = new MessageQueue()) 
      { 
       msmq.Send(workflowCreated); 
       msmq.Close(); 

       // MsmqHelper.DisposeQueue(msmq); 

       // 3. You should explicitly call Close object to immediately release  
       // unmanaged resources, while managed ones will be released 
       // at next GC rounds, as soon as possible 
      } 
     } 
     //private MessageQueue _messageQueue; 

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

     //private void Dispose(bool disposing) 
     //{ 
    // if (disposing == false) { return; } 
    // 
    // MsmqHelper.DisposeQueue(this._messageQueue); 
    //} 

    //public static void DisposeQueue(MessageQueue messageQueue) 
    //{ 
    // if (messageQueue != null) 
    // { 
    //  messageQueue.Close(); 
    //  messageQueue.Dispose(); 
    //  messageQueue = null; 
    // } 
    //} 
} 
+0

Artur and Jim:あなたの答えをありがとう。あなたの提案を使用するように実装を変更します。あなたの答えはなぜ私が1つのケースでCAエラーを取得するのか説明していませんが、他のケースでは解決できません。問題は、同じコードがあるメソッドではコンパイルされますが、他のメソッドではコンパイルされないということです。 –

関連する問題