2012-03-20 16 views
5

से अधिक का खुलासा किया है मैंने इस त्रुटि को अन्य पदों पर देखा है, लेकिन इस सटीक स्थिति के लिए नहीं।संदेश क्यूई एक बार

मेरे पास दो वर्ग हैं जो MessageQueue के साथ एक ही काम करते हैं। इसके कारण, मैंने एक सहायक वर्ग में कतार के निर्माण और निपटान को सारणित किया। मुझे यह त्रुटि मिल रही है, और मैं नहीं देख सकता कि कतार को एक से अधिक बार कैसे निपटाया जा सकता है।

private MessageQueue _messageQueue; 

तब:

वस्तु 'messageQueue' विधि में एक बार 'MsmqHelper.DisposeQueue (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); 
} 

और यह सहायक वर्ग है कि वास्तव में निपटान कॉल() में कोड है:

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

कहाँ कतार के लिए यह संभव है इस स्थिति में एक से अधिक बार निपटान किया जाना है?

** संपादित करें **

मैंने सोचा कि यह यहाँ मेरी टिप्पणी जोड़ने के लिए नीचे दिए गए बातचीत में, अच्छा होगा। स्वीकार्य उत्तर के साथ यह एक अच्छा सारांश है:

मुझे लगता है कि मुझे अब यह मिल गया है। MessageQueue विधि पैरामीटर के पास ऑब्जेक्ट के मूल (this._messageQueue) संदर्भ के साथ कुछ लेना देना नहीं है। तो शून्य के लिए संदेश क्यूई जांचना, और इसे शून्य पर सेट करना, अच्छा नहीं है। कॉलर अभी भी इसके वैरिएबल (this._messageQueue) में डिस्पोजेड होने के बाद भी पास हो सकता है। इसलिए, एक से अधिक बार निपटान करने में सक्षम होने के नाते।

वैसे भी, कॉल करने वाले विधि में यह कॉलर के चर (this._messageQueue) को शून्य तक सेट करने से भी मदद नहीं करता है। समस्या पूरी तरह से MsmqHelper.DisposeQueue() में मौजूद है। तो जवाब रेफरी से गुज़रना है या बस DisposeQueue() को कॉल नहीं करना है और इसे कॉलिंग विधि में करना है।

** संपादित 2 **

इस कोशिश कर के बाद, मैं एक ही त्रुटि मिलती है। मुझे बस यह नहीं मिला।

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

    messageQueue.Close(); 
    messageQueue.Dispose(); 
    messageQueue = null; 
} 

** संपादित 3 - बग? **

मुझे लगता है कि यह एक बग हो सकता है। अगर मैं MessageQueue टिप्पणी करता हूं।(), त्रुटि दूर हो जाती है। हालांकि, मैं कॉल संदेश Queue.Close() और messageQueue। विधि पर कॉल करके() को एक साथ जोड़ें। जाओ पता लगाओ। मुझे लगता है कि मैं सिर्फ कॉलिंग विधियों से ये वही कॉल करने जा रहा हूं, या दोनों के बजाय केवल बंद करें() या निपटान() को कॉल करें।

+0

जहां 'सार्वजनिक शून्य निपटान() (बूल निपटान)' विधि परिभाषित किया गया है? – Tigran

+0

क्या यह संभवतः हो सकता है क्योंकि 'बंद करें' और 'निपटान' वही काम करता है? –

+0

@Lasse यह एक दिलचस्प विचार है। मैंने बंद() लाइन पर टिप्पणी की और इसे संकलित किया। तब मैंने बंद() लाइन को असम्बद्ध किया, और निपटान() लाइन पर टिप्पणी की और यह अभी भी संकलित है। तो आपने जो कहा वह जवाब हो सकता है। मैं शपथ ले सकता था कि मेरे पास पिछले कोड में दोनों लाइनें (बंद() और निपटान()) थीं और यह काम करती थी। मैंने अभी जांच की, और मैंने किया। अब मुझे यकीन नहीं है कि क्या सोचना चाहिए। –

उत्तर

2

बंद MessageQueue वस्तु के सभी संसाधनों को मुक्त कर देते: आप डिस्पोजेबल पैटर्न के साथ गंदगी को, आप बस इसे

उपयोग कर सकते हैं और अपने कोड इस तरह सरल किया जा सकता है की जरूरत नहीं है। documentation here देखें। सीए में उत्पन्न होने वाली त्रुटि सबसे अधिक संभावना है क्योंकि यह देखता है कि बंद करने का निष्पादन पथ भी निपटान करता है।

प्रलेखन से:

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 खोलने के ऊपरी हिस्से को हटा देती है।

* अद्यतन * ऐसा लगता है कि सीए एक पद्धति के लिए डिस्पोजेबल वस्तु गुजर, भले ही उस विधि वर्ग के लिए निजी है बनाम सदस्य क्षेत्रों के लिए अलग तरह से CA2202 व्यवहार करता है। भले ही, दस्तावेज़ीकरण के अनुसार, आपको केवल बंद() या निपटान() को कॉल करना होगा, लेकिन दोनों नहीं। हालांकि मैं आपके डिज़ाइन को बदलने की सलाह देता हूं ताकि आप संदेश क्यूई ऑब्जेक्ट को अपने संदेश संचालन के दायरे में बना सकें, उपयोग कर सकें और फिर बंद कर सकें जैसे दस्तावेज़ीकरण उदाहरण से उदाहरण ऊपर दिखाता है।

+1

मैंने सोचा कि भी, लेकिन यह मामला नहीं है। ऊपर मेरा संपादन 3 देखें। –

+0

आप दोनों सफलतापूर्वक कॉल कर सकते हैं लेकिन क्यों सीए एक मामले में पकड़ रहा है और अन्य कोई भी मेरे बाहर नहीं है। ऐसा कहा जा रहा है कि, आपको शायद संदेश क्यूई खोलना चाहिए, इसका इस्तेमाल करना चाहिए, और जितनी जल्दी हो सके इसे बंद या निपटाना चाहिए। केवल तभी उपयोग करें जब आपका परिदृश्य कचरा संग्रहण से पहले संसाधन को पुनः प्राप्त करने के लिए कहता है।अन्यथा, कनेक्शन कैशिंग एक अगली MessageQueue ऑब्जेक्ट को छोटे ओवरहेड के साथ फिर से बनाया/खोला जा सकता है। – Jim

+1

धन्यवाद, जिम। मैं आपका जवाब स्वीकार कर रहा हूं क्योंकि इससे स्थिति की सबसे अधिक समझ होती है: "ऐसा प्रतीत होता है कि सीए एक विधि के लिए डिस्पोजेबल ऑब्जेक्ट को गुजरने के विरुद्ध सदस्य क्षेत्रों के लिए सीए 2202 अलग-अलग व्यवहार करता है, भले ही वह विधि कक्षा के लिए निजी हो।" –

2

हां।इस वस्तु को कई बार नष्ट कर सकें:

मूल्य कि this._messageQueue का मूल्यांकन करता है करने के लिए MsmqHelper.DisposeQueue(this._messageQueue) लागू करने के बाद नहीं बदल जाती है।

केवल स्थानीय पैरामीटर (messageQueue नाम) DisposeQueue विधि में मूल्य null सौंपा गया था। इस प्रकार "शून्य गार्ड" आसपास के समय के आसपास सही ढंग से गार्ड करने में विफल रहता है। (इसका कारण यह है सी # के डिफ़ॉल्ट व्यवहार Call-By-Value है: कृपया लिंक को समझने के लिए इस "एक वस्तु के लिए एक संदर्भ के मूल्य में गुजर" के संदर्भ में इसका मतलब है देखते हैं।)

या तो ref में लेने के लिए या फोन करने वाले में this._messageQueue = null आवंटित। MessageQueue वर्ग IDisposable iterface लागू करता

+0

आह, इसलिए मैं कतार को शून्य पर सेट नहीं कर रहा था, मैं चर (ऑब्जेक्ट पर पॉइंटर) को शून्य पर सेट कर रहा था। और मैं केवल DisposeQueue() विधि में पैरामीटर के लिए ऐसा कर रहा था। इसका मतलब है कि यह ._messageQueue अभी भी संदर्भ को इंगित कर रहा था, और कभी भी शून्य पर सेट नहीं हुआ। क्या वह सही है? –

+0

एक * कभी * ऑब्जेक्ट को शून्य पर सेट करता है - केवल चर ;-) 'this._messageQueue' अभी भी * उसी ऑब्जेक्ट का मूल्यांकन करता है जैसा कि पहले किया गया था, हां। ("मूल्यांकन" को वर्ग प्रकारों के बारे में बात करते समय "संदर्भ को स्टोर किया जा सकता है" के रूप में पढ़ा जा सकता है।) –

+0

ध्यान दें कि कंपाइलर 'DisposeQueue' विधि के बारे में शिकायत कर रहा है, और यह विधि केवल ऑब्जेक्ट को एक से अधिक बार निपटान करेगी यदि वास्तव में * एक बार से अधिक * कहा जाता है, लेकिन शिकायत विधि के बारे में है, इसके बारे में कई कॉल नहीं। मुझे लगता है कि यह अधिक संभावना है कि चेतावनी लगभग 'बंद' और 'निपटान' दोनों को एक ही चीज़ (यानी वस्तु का निपटान करने के बावजूद) कहा जा रहा है। –

1

हैं, तो और स्पष्ट रूप से निपटान विधि का उपयोग करने कोई मतलब नहीं बंद() विधि क्योंकि इस तरह सभी वर्गों बंद() विधि आमतौर पर है में है, न कि किसी iterface विधि बल्कि एक वर्ग विधि है, । आम तौर पर, निपटान विधि में सभी सही अपमान को रिलीज प्रबंधित/अप्रबंधित संसाधनों से पहले बंद() mehod को कॉल करना चाहिए।

फिर से, बाहरी स्थैतिक सहायक को प्रेरित करके, आप डिस्पोजेबल पैटर्न को तोड़ देते हैं। वस्तु के जीवनकाल को नियंत्रित करने का यह सही तरीका नहीं है;

// 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

आर्टूर और जिम: आपके उत्तरों के लिए धन्यवाद। मैं आपके सुझाव का उपयोग करने के लिए अपना कार्यान्वयन बदल रहा हूं। जबकि आपके उत्तरों में यह स्पष्ट नहीं किया गया है कि मुझे एक मामले में सीए त्रुटि क्यों मिलती है, लेकिन दूसरी नहीं, आपके उत्तर अभी भी मदद करते हैं। मुद्दा यह है कि एक ही कोड में एक ही कोड संकलित होता है, लेकिन दूसरा नहीं। –

संबंधित मुद्दे