2015-12-22 9 views
11

मैं VB.NET 14 में निम्नलिखित WPF नमूना एप्लिकेशन लिखा VS2015.1 पर नेट 4.6.1 का उपयोग कर:IDisposable.Dispose() async विधि के लिए रिलीज मोड में नहीं बुलाया

Class MainWindow 

    Public Sub New() 
     InitializeComponent() 
    End Sub 

    Private Async Sub Button_Click(sender As Object, e As RoutedEventArgs) 
     MessageBox.Show("Pre") 

     Using window = New DisposableWindow() 
      window.Show() 

      For index = 1 To 1 
       Await Task.Delay(100) 
      Next 
     End Using 

     MessageBox.Show("Post") 
    End Sub 

    Class DisposableWindow 
     Inherits Window 
     Implements IDisposable 

     Public Sub Dispose() Implements IDisposable.Dispose 
      Me.Close() 
      MessageBox.Show("Disposed") 
     End Sub 
    End Class 

End Class 

नमूना नीचे का उत्पादन निम्नलिखित उत्पादन:

  • डीबग मोड: पूर्व, निपटाई गई, पोस्ट
  • रिलीज मोड: पूर्व, डाक

यह वह जगह है अजीब। डीबग मोड इस कोड को रिलीज मोड से अलग तरीके से निष्पादित क्यों करेगा ...?

जब मैं एक मैनुअल कोशिश करने के लिए ब्लॉक का उपयोग बदलने के/अंत में ब्लॉक, window.Dispose (करने के लिए कॉल) भी एक NullReferenceException फेंकता है:

Dim window = New DisposableWindow() 
Try 
    window.Show() 

    For index = 1 To 1 
     Await Task.Delay(100) 
    Next 
Finally 
    window.Dispose() 
End Try 

और भी अधिक अजीब सामान: जब के लिए लूप है बाहर रखा गया, नमूना पूरी तरह से काम करता है। मैंने केवल फोर्स-लूप को एक बार चलाने दिया है, ताकि कम से कम लूप को समस्या उत्पन्न हो सके। थोड़ी देर के लिए फॉर-लूप को प्रतिस्थापित करने के लिए भी स्वतंत्र महसूस करें। यह फोर-लूप के समान व्यवहार करता है।

काम करता है:

Using window = New DisposableWindow() 
    window.Show() 

    Await Task.Delay(100) 
End Using 

अब आप सोच सकते हैं: 'यह अजीब है!'। यह और भी बदतर हो जाता है। मैंने सी # (6) में भी वही उदाहरण बनाया है, जहां यह पूरी तरह से काम करता है। तो सी # में डीबग और रिलीज मोड दोनों के परिणामस्वरूप 'प्री, डिस्प्लेड, पोस्ट' आउटपुट के रूप में होता है।

नमूने यहाँ डाउनलोड किया जा सकता है:

http://www.filedropper.com/vbsample

http://www.filedropper.com/cssample

मैं बहुत इस बिंदु पर स्टम्प्ड रहा हूँ। क्या यह .NET Framework के VB.NET स्टैक में एक बग है? या क्या मैं कुछ अजीब काम करने की कोशिश कर रहा हूं, जो भाग्य से सी # में काम करता है और आंशिक रूप से वीबी.नेट में?

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

कुछ और परीक्षण किया:

  • रिलीज मोड के लिए VB.NET में संकलक अनुकूलन अक्षम करना, यह डीबग मोड की तरह व्यवहार की उम्मीद के रूप में बनाता है (, लेकिन यह परीक्षण करने के लिए चाहता था, शायद ज़रुरत पड़े)।
  • समस्या तब भी होती है जब मैं .NET 4.5 को लक्षित करता हूं (सबसे पुराना संस्करण जहां async/await उपलब्ध हो गया था)।

अद्यतन:

इस के बाद से निर्धारित किया गया है। संस्करण 1.2 के लिए सार्वजनिक रिलीज की योजना बनाई गई है, लेकिन मास्टर शाखा में नवीनतम संस्करण में फिक्स होना चाहिए।

देखें: https://github.com/dotnet/roslyn/issues/7669

+0

सिर्फ एक कूबड़ है, लेकिन ऐसा लगता है कि निपटान() कॉल एक अलग धागे पर है। डीबग में काम करने का कारण यह है कि डीबगर आपके लिए थ्रेड स्विच कर रहा है। यदि आपने कुछ प्रकार के कॉलबैक जोड़े हैं जो आपको सही धागे पर वापस ले जाते हैं तो आपको बेहतर भाग्य मिल सकता है। – sapbucket

+0

उदाहरण के लिए, कैसे कोड का उपयोग करता आह्वान आवश्यक देखें: http://stackoverflow.com/questions/3874134/cleaning-up-code-littered-with-invokerequired – sapbucket

+0

@sapbucket: उचित लगता है, लेकिन यही कारण है कि यह स्पष्ट नहीं होता सी # में काम करता है। दोनों भाषाओं को एक ही एमएसआईएल के बारे में संकलित करना चाहिए, है ना? रुको, यह मुझे एक विचार देता है: मुझे एमएसआईएल की तुलना करनी चाहिए। मैं बाद में कोशिश करूंगा! –

उत्तर

12

मैं इस एक अप लिखेंगे, इस रोसलिन बग निहायत गंदा और उत्तरदायी VB.NET कार्यक्रमों का एक बहुत तोड़ने के लिए है। एक बहुत बदसूरत और रास्ते का निदान करने में मुश्किल है।

बग देखना बहुत मुश्किल है, तो आप एक decompiler साथ उत्पन्न विधानसभा को देखने के लिए की है। मैं ब्रेक-गर्दन की गति पर इसका वर्णन करूंगा। Async Sub में बयान एक राज्य मशीन में फिर से लिखा जाता है, आपके स्निपेट में विशिष्ट वर्ग का नाम VB $ StateMachine_1_buttonClick है। आप इसे केवल एक सभ्य डिकंपेलर के साथ देख सकते हैं। इस वर्ग की MoveNext() विधि विधि निकाय में बयान निष्पादित करती है। यह एसिंक कोड चलाते समय यह विधि कई बार दर्ज की जाती है।

MoveNext() द्वारा उपयोग किए जाने वाले चर पर कब्जा करने की आवश्यकता है, जिससे आपके स्थानीय चर वर्ग के क्षेत्रों में बदल जाते हैं। आपके window वैरिएबल की तरह, इसका उपयोग बाद में आवश्यक होगा जब उपयोग कथन समाप्त होता है और निपटान() विधि को कॉल करने की आवश्यकता होती है। डीबग बिल्ड में इस चर का नाम $VB$ResumableLocal_window$0 है। जब आप अपने प्रोग्राम के रिलीज बिल्ड का निर्माण करते हैं, तो संकलक इस वर्ग को अनुकूलित करने और बुरी तरह खराब होने का प्रयास करता है। यह कब्जा निकल जाते हैं और window MoveNext की एक स्थानीय चर बनाता है()। यह बहुत गलत है, जब Await के बाद निष्पादन फिर से शुरू होता है, तो वह चर कुछ भी नहीं होगा। और इस प्रकार इसका निपटान() विधि नहीं कहा जाएगा।

यह रोज़लिन बग का बहुत बड़ा असर पड़ता है, यह किसी भी वीबीएनईटी कोड को तोड़ देगा जो Using कथन को असिनक विधि में उपयोग करता है जहां कथन निकाय में एक प्रतीक्षा है। निदान करना आसान नहीं है, एक लापता निपटान() कॉल अक्सर ज्ञात नहीं जाता है। आपके जैसे मामले में छोड़कर जहां यह एक बहुत ही दृश्यमान दुष्प्रभाव है। उत्पादन में चल रहे बहुत से प्रोग्राम होने चाहिए, जिनके पास अभी यह बग है। साइड इफेक्ट यह है कि वे "भारी" चलाएंगे, जो आवश्यकतानुसार अधिक संसाधनों का उपभोग करेंगे। कार्यक्रम कई तरीकों से निदान करने में कठोर हो सकता है।

इस बग के लिए एक अस्थायी समाधान है, अपने VB.NET अनुप्रयोग, कि अन्य समस्या है की डीबग बिल्ड तैनात कभी नहीं करना सुनिश्चित करें। इसके बजाय अनुकूलक बंद करें। रिलीज बिल्ड का चयन करें और प्रोजेक्ट> प्रॉपर्टीज> कंपाइल टैब> उन्नत कंपाइल विकल्प> "ऑप्टिमाइज़ेशन सक्षम करें" चेकबॉक्स का चयन करें।

ओह, यह बुरा है।

+0

वाह, वह बदसूरत लगता है। मैं वास्तव में उत्सुक हूं कि यह केवल तब होता है जब प्रतीक्षा कथन किसी के लिए या लूप में होता है। मुझे भी यकीन है कि रोज़लिन टीम आपके विश्लेषण से प्यार करेगी! –

+2

यह बहुत बदसूरत है। फॉर/जबकि लूप बग में भी महत्वपूर्ण भूमिका निभा सकता है, मैंने इसके दुष्प्रभावों का विश्लेषण करने के लिए पर्याप्त गहराई से खोद नहीं पाया। शायद समझाओ कि बग पहले क्यों नहीं मिला है। Rosynn कोड जो आपके Async सब को फिर से लिखता है वह बेहद गैर-तुच्छ है, इस प्रकार के कोड ट्रांसफॉर्मेशन एक जटिल व्यक्ति को सबसे जटिल चीज है। –

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