रोजलिन कोड संकलित करने में विफल रहे


95

जब मैंने अपने प्रोजेक्ट को VS2013 से VS2015 में माइग्रेट कर लिया है, तो प्रोजेक्ट अब नहीं बनता। निम्नलिखित LINQ कथन में एक संकलन त्रुटि होती है:

static void Main(string[] args)
{
    decimal a, b;
    IEnumerable<dynamic> array = new string[] { "10", "20", "30" };
    var result = (from v in array
                  where decimal.TryParse(v, out a) && decimal.TryParse("15", out b) && a <= b // Error here
                  orderby decimal.Parse(v)
                  select v).ToArray();
}

संकलक त्रुटि देता है:

CS0165 त्रुटि रहित स्थानीय चर 'b' का उपयोग

इस मुद्दे का क्या कारण है? क्या एक संकलक सेटिंग के माध्यम से इसे ठीक करना संभव है?


11
@BinaryWorrier: क्यों? यह केवल bएक outपैरामीटर के माध्यम से असाइन करने के बाद उपयोग करता है ।
जॉन स्कीट

1
वीएस 2015 दस्तावेज में कहा गया है, "हालांकि चर के रूप में पारित किए गए तर्कों को पारित होने से पहले आरंभ करने की आवश्यकता नहीं है, विधि के वापस आने से पहले एक मूल्य को निर्दिष्ट करने के लिए बुलाया विधि की आवश्यकता होती है।" तो यह एक बग की तरह दिखता है हाँ, यह उस ट्रायपर्स द्वारा आरंभ करने की गारंटी है।
रूप

3
त्रुटि के बावजूद, इस कोड ने outतर्कों के बारे में जो कुछ भी बुरा है, उसका अनुकरण किया। क्या वह एक TryParseअशक्त मान (या समतुल्य) लौटाएगा।
कोनराड रूडोल्फ

1
@KonradRudolph where (a = decimal.TryParse(v)).HasValue && (b = decimal.TryParse(v)).HasValue && a <= bलग रहा है ज्यादा बेहतर
Rawling

2
बस ध्यान दें, आप इसे सरल कर सकते हैं decimal a, b; var q = decimal.TryParse((dynamic)"10", out a) && decimal.TryParse("15", out b) && a <= b;। मैंने एक रोसलिन बग खोल दिया है ।
17

जवाबों:


112

इस मुद्दे का क्या कारण है?

मेरे लिए एक कंपाइलर बग जैसा दिखता है। कम से कम, यह किया था। यद्यपि समय decimal.TryParse(v, out a)और decimal.TryParse(v, out b)अभिव्यक्तियों का गतिशील रूप से मूल्यांकन किया जाता है, मुझे उम्मीद है कि कंपाइलर को अभी भी यह समझना होगा कि जब तक यह पहुंचता है a <= b, तब तक aऔर bनिश्चित रूप से दोनों को सौंपा जाता है। यहां तक ​​कि आप अजीब टाइपिंग के साथ डायनामिक टाइपिंग में आ सकते हैं, मुझे उम्मीद है कि a <= bदोनों TryParseकॉल्स का मूल्यांकन करने के बाद ही आप कभी भी मूल्यांकन करेंगे ।

हालांकि, यह पता चला है कि ऑपरेटर और रूपांतरण ट्रिकी के माध्यम से, यह अभिव्यक्ति के लिए पूरी तरह से संभव है A && B && Cजो मूल्यांकन करता है Aऔर Cनहीं B- लेकिन यदि आप पर्याप्त चालाक हैं। नील गैटर के सरल उदाहरण के लिए रोसलिन बग रिपोर्ट देखें ।

उस कार्य को dynamicकरना और भी कठिन होता है - जब ऑपरेंड गतिशील होते हैं तो इसमें शामिल शब्दार्थ का वर्णन करना कठिन होता है, क्योंकि ओवरलोड रिज़ॉल्यूशन करने के लिए, आपको यह जानने के लिए ऑपरेंड का मूल्यांकन करना होगा कि कौन-कौन से प्रकार शामिल हैं, जो प्रति-सहज हो सकते हैं। हालांकि, फिर से नील एक उदाहरण के साथ आया है जो दिखाता है कि संकलक त्रुटि की आवश्यकता है ... यह एक बग नहीं है, यह एक बग फिक्स है । इसे साबित करने के लिए नील को भारी मात्रा में कुदोस।

क्या संकलक सेटिंग्स के माध्यम से इसे ठीक करना संभव है?

नहीं, लेकिन ऐसे विकल्प हैं जो त्रुटि से बचते हैं।

सबसे पहले, आपको यह गतिशील होने से रोक सकता है - यदि आप जानते हैं कि आप केवल कभी तार का उपयोग करेंगे, तो आप इस्तेमाल कर सकते हैं IEnumerable<string> या सीमा चर देने vका एक प्रकार है string(यानी from string v in array)। यह मेरा पसंदीदा विकल्प होगा।

यदि आपको वास्तव में इसे गतिशील रखने की आवश्यकता है, तो बस इसके bसाथ शुरू करने के लिए एक मूल्य दें :

decimal a, b = 0m;

यह कोई नुकसान नहीं पहुंचाएगा - हम जानते हैं कि वास्तव में आपका गतिशील मूल्यांकन कुछ भी पागल नहीं करेगा, इसलिए आप अभी भी bइसका उपयोग करने से पहले एक मूल्य असाइन करना शुरू कर देंगे , जिससे प्रारंभिक मूल्य अप्रासंगिक हो जाएगा।

इसके अतिरिक्त, ऐसा लगता है कि कोष्ठक जोड़ना भी काम करता है:

where decimal.TryParse(v, out a) && (decimal.TryParse("15", out b) && a <= b)

यह उस बिंदु को बदल देता है जिस पर ओवरलोड रिज़ॉल्यूशन के विभिन्न टुकड़े ट्रिगर होते हैं, और कंपाइलर को खुश करने के लिए होता है।

नहीं है एक समस्या अभी भी शेष - साथ निश्चित काम पर कल्पना के नियमों &&ऑपरेटर की जरूरत राज्य के लिए स्पष्ट किया है कि वे केवल जब लागू &&ऑपरेटर दो के साथ अपने "नियमित" कार्यान्वयन में किया जा रहा है boolऑपरेंड। मैं यह सुनिश्चित करने की कोशिश करूंगा कि यह अगले ECMA मानक के लिए तय हो।


हाँ! IEnumerable<string>कोष्ठक लगाना या जोड़ना मेरे लिए काम करता है। अब संकलक त्रुटि के बिना बनाता है।
ramil89

1
उपयोग decimal a, b = 0m;करने से त्रुटि दूर हो सकती है, लेकिन तब a <= bहमेशा उपयोग होता है 0m, क्योंकि आउट मूल्य की गणना अभी तक नहीं की गई है।
पवन बाल्टजर्सन

12
@PawBaltzersen: आपको क्या लगता है? यह हमेशा तुलना से पहले सौंपा जाएगा - यह सिर्फ इतना है कि संकलक इसे साबित नहीं कर सकता है, किसी कारण से (एक बग, मूल रूप से)।
जॉन स्कीट

1
एक साइड इफेक्ट के बिना एक पार्सिंग विधि होने यानी। decimal? TryParseDecimal(string txt)इसका समाधान भी हो सकता है
ज़ाहिर

1
मुझे आश्चर्य है कि यह आलसी आरंभीकरण है; यह सोचता है "यदि पहला सच है तो मुझे दूसरे का मूल्यांकन करने की आवश्यकता नहीं है जिसका अर्थ है bकि असाइन नहीं किया जा सकता है"; मुझे पता है कि यह अमान्य तर्क है लेकिन यह बताता है कि कोष्ठक इसे ठीक क्यों करते हैं ...
ड्यूर्रोन 597

21

यह रोजलिन कंपाइलर में बग, या कम से कम प्रतिगमन प्रतीत होता है। इसे ट्रैक करने के लिए निम्न बग दर्ज किया गया है:

https://github.com/dotnet/roslyn/issues/4509

इस बीच, जॉन के उत्कृष्ट उत्तर में चारों ओर काम की एक जोड़ी है।


इसके अलावा यह बग जो यह नोट करता है कि यह LINQ के साथ क्या करना है ...
18

16

चूंकि बग रिपोर्ट में मुझे इतनी मेहनत मिली है, इसलिए मैं इसे स्वयं समझाने की कोशिश करने जा रहा हूं।


कल्पना करें Tकि कुछ उपयोगकर्ता-परिभाषित प्रकार हैं, जिनमें निहित boolविकल्पों के साथ एक अंतर्निहित कलाकारों के साथ falseऔर true, के साथ शुरू होता है false। जहां तक ​​संकलक को पता है, dynamicपहले तर्क में &&उस प्रकार का मूल्यांकन हो सकता है, इसलिए इसे निराशावादी होना चाहिए।

यदि, तब, यह कोड को संकलित करता है, तो यह हो सकता है:

  • जब गतिशील बांधने वाला पहले का मूल्यांकन &&करता है, तो यह निम्न कार्य करता है:
    • पहले तर्क का मूल्यांकन करें
    • यह एक है T- संक्षेप में यह करने के लिए डाली bool
    • ओह, यह है false, इसलिए हमें दूसरे तर्क का मूल्यांकन करने की आवश्यकता नहीं है।
    • &&पहले तर्क के रूप में मूल्यांकन का परिणाम बनाएं । (नहीं, falseकिसी कारण से नहीं।)
  • जब डायनेमिक बाइंडर दूसरे का मूल्यांकन &&करता है, तो यह निम्न कार्य करता है:
    • पहले तर्क का मूल्यांकन करें।
    • यह एक है T- संक्षेप में यह करने के लिए डाली bool
    • ओह, यह है true, इसलिए दूसरे तर्क का मूल्यांकन करें।
    • ... अरे बकवास, bसौंपा नहीं है।

संक्षेप में, संक्षेप में, विशेष "निश्चित असाइनमेंट" नियम हैं जो हमें न केवल यह कहते हैं कि एक चर "निश्चित रूप से सौंपा गया है" या "निश्चित रूप से असाइन नहीं किया गया है", लेकिन यह भी कि अगर यह "निश्चित रूप से falseकथन के बाद सौंपा गया है" या "निश्चित रूप से" trueबयान के बाद सौंपा "।

ये तो मौजूद है कि जब से निपटने &&और ||(और !और ??और ?:) संकलक जांच कर सकते हैं कि क्या चर एक जटिल बूलियन अभिव्यक्ति की विशेष शाखाओं में सौंपा जा सकता है।

हालांकि, ये केवल काम करते हैं जबकि भावों के प्रकार बूलियन होते हैं । जब अभिव्यक्ति का हिस्सा होता है dynamic(या एक गैर-बूलियन स्थैतिक प्रकार), तो हम अब मज़बूती से यह नहीं कह सकते हैं कि अभिव्यक्ति है trueया false- अगली बार जब हम यह boolतय करने के लिए डालते हैं कि किस शाखा को लेना है, तो इससे उसका मन बदल सकता है।


अद्यतन: यह अब हल हो गया है और प्रलेखित है :

गतिशील अभिव्यक्तियों के लिए पिछले संकलक द्वारा कार्यान्वित निश्चित असाइनमेंट नियमों ने कोड के कुछ मामलों की अनुमति दी जिसके परिणामस्वरूप चर पढ़े जा सकते हैं जो निश्चित रूप से असाइन नहीं किए गए हैं। इसकी एक रिपोर्ट के लिए https://github.com/dotnet/roslyn/issues/4509 देखें ।

...

इस संभावना के कारण कि कंपाइलर को इस प्रोग्राम को संकलित करने की अनुमति नहीं देनी चाहिए यदि वैल का कोई प्रारंभिक मूल्य नहीं है। संकलक के पिछले संस्करणों (VS2015 से पहले) ने इस कार्यक्रम को संकलन करने की अनुमति दी, भले ही वैल का कोई प्रारंभिक मूल्य न हो। रोसलिन अब इस प्रयास का निदान करती है कि संभवतः एक अनइंस्टॉल किए गए चर को पढ़ें।


1
अपनी अन्य मशीन पर VS2013 का उपयोग करते हुए, मैं वास्तव में इस का उपयोग करते हुए अप्रकाशित मेमोरी को पढ़ने में कामयाब रहा हूं। यह बहुत ही रोमांचक नहीं है :(
रॉलिंग

आप साधारण डेलीगेट के साथ बिना पढ़े हुए वैरिएबल पढ़ सकते हैं। एक प्रतिनिधि बनाएँ जो outएक विधि के पास हो ref। यह ख़ुशी से करेगा, और यह बिना मूल्य को बदले, चर को नियत कर देगा।
IllidanS4, मोनिका को

जिज्ञासा से बाहर, मैंने उस स्निपेट को C # v4 के साथ परीक्षण किया। जिज्ञासा से बाहर, हालांकि - संकलक ऑपरेटर का उपयोग करने का निर्णय कैसे करता है false/ trueनिहित कलाकारों के ऑपरेटर के विपरीत? स्थानीय रूप से, यह implicit operator boolपहले तर्क पर कॉल करेगा , फिर दूसरे ऑपरेंड operator falseपर कॉल करेगा, पहले ऑपरेंड पर कॉल करेगा, उसके बाद implicit operator boolपहले ऑपरेंड पर फिर से । इससे मुझे कोई मतलब नहीं है, पहले ऑपरेंड को अनिवार्य रूप से एक बार बूलियन को उबालना चाहिए, नहीं?
रोब

@ रोब यह है dynamic, जंजीर- &&मामला? मैंने देखा है कि मूल रूप से जाना (1) पहले तर्क का मूल्यांकन करें (2) अंतर्निहित कलाकारों का उपयोग करके देखें कि क्या मैं शॉर्ट सर्किट कर सकता हूं (3) मैं नहीं कर सकता, इसलिए दूसरे तर्क को स्पष्ट करें (4) अब मैं दोनों प्रकार जानता हूं, मैं देख सकते हैं सबसे अच्छा &&है एक उपयोगकर्ता-परिभाषित &(5) कॉल ऑपरेटर falseपहले तर्क पर यह देखने के लिए कि क्या मैं शॉर्ट सर्किट (6) कर सकता हूं (क्योंकि falseऔर implicit boolअसहमत), इसलिए परिणाम पहले तर्क है ... और फिर अगला &&, (7) अगर मैं शॉर्ट सर्किट (फिर से) कर सकता हूं, तो यह देखने के लिए निहित कलाकारों का उपयोग करें।
Rawling

@ IllidanS4 दिलचस्प लगता है, लेकिन मुझे यह नहीं पता है कि यह कैसे करना है। क्या आप मुझे एक स्निपेट दे सकते हैं?
7

15

यह एक बग नहीं है। उदाहरण के लिए https://github.com/dotnet/roslyn/issues/4509#issuecomment-130872713 देखें कि इस रूप की एक गतिशील अभिव्यक्ति कैसे इस तरह के एक आउट चर को छोड़ सकती है।


1
जैसा कि मेरा उत्तर स्वीकार किया जाता है और अत्यधिक उत्थान किया जाता है, मैंने संकल्प को इंगित करने के लिए इसे संपादित किया है। इस पर आपके सभी काम के लिए धन्यवाद - मुझे मेरी गलती समझाने सहित :)
जॉन स्केट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.