ऐसा क्यों होता है? (अशक्त ||! TryParse) सशर्त परिणाम "अप्रमाणित स्थानीय चर का उपयोग"?


98

निम्नलिखित कोड के परिणाम के बिना उपयोग किए गए स्थानीय वैरिएबल "numberOfGroups" :

int numberOfGroups;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
    numberOfGroups = 10;
}

हालाँकि, यह कोड ठीक काम करता है (हालाँकि, ReSharper का कहना है कि = 10यह बेमानी है):

int numberOfGroups = 10;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
    numberOfGroups = 10;
}

क्या मुझे कुछ याद आ रहा है, या संकलक मुझे पसंद नहीं कर रहा है ||?

मैंने इसे dynamicसमस्याओं के कारण सीमित कर दिया है ( optionsमेरे उपरोक्त कोड में एक गतिशील चर था)। सवाल अभी भी बना हुआ है, मैं ऐसा क्यों नहीं कर सकता ?

यह कोड संकलित नहीं करता है :

internal class Program
{
    #region Static Methods

    private static void Main(string[] args)
    {
        dynamic myString = args[0];

        int myInt;
        if(myString == null || !int.TryParse(myString, out myInt))
        {
            myInt = 10;
        }

        Console.WriteLine(myInt);
    }

    #endregion
}

हालाँकि, यह कोड करता है :

internal class Program
{
    #region Static Methods

    private static void Main(string[] args)
    {
        var myString = args[0]; // var would be string

        int myInt;
        if(myString == null || !int.TryParse(myString, out myInt))
        {
            myInt = 10;
        }

        Console.WriteLine(myInt);
    }

    #endregion
}

मुझे नहीं लगा कि इसमें dynamicकोई कारक होगा।


यह मत समझ लेना कि यह जानने के लिए पर्याप्त स्मार्ट है कि आप outइनपुट के रूप में अपने परम में पारित मूल्य का उपयोग नहीं कर रहे हैं
चरलेह

3
यहां दिया गया कोड वर्णित व्यवहार को प्रदर्शित नहीं करता है; यह ठीक काम करता है। कृपया उस कोड को पोस्ट करें जो वास्तव में आपके द्वारा बताए गए व्यवहार को प्रदर्शित करता है जिसे हम स्वयं संकलित कर सकते हैं। हमें पूरी फाइल दे दो।
एरिक लिपर्ट

8
आह, अब हमारे पास कुछ दिलचस्प है!
एरिक लिपर्ट

1
यह बहुत आश्चर्य की बात नहीं है कि संकलक इससे भ्रमित है। डायनामिक कॉल साइट के लिए सहायक कोड में शायद कुछ नियंत्रण प्रवाह होते हैं जो outपरम को असाइनमेंट की गारंटी नहीं देते हैं । यह विचार करना दिलचस्प है कि समस्या से बचने के लिए कंपाइलर को किस सहायक कोड का उत्पादन करना चाहिए, या यदि संभव हो तो।
कोडइन्चोस

1
पहली नज़र में यह निश्चित है कि यह बग जैसा दिख रहा है।
एरिक लिपर्ट

जवाबों:


73

मुझे पूरा यकीन है कि यह एक कंपाइलर बग है। अच्छा लगा!

संपादित करें: यह एक बग नहीं है, जैसा कि क्वार्टरमेस्टर प्रदर्शित करता है; डायनेमिक एक अजीब trueऑपरेटर को लागू कर सकता है जो yकभी भी आरंभिक नहीं हो सकता है।

यहाँ एक न्यूनतम रेपो है:

class Program
{
    static bool M(out int x) 
    { 
        x = 123; 
        return true; 
    }
    static int N(dynamic d)
    {
        int y;
        if(d || M(out y))
            y = 10;
        return y; 
    }
}

मुझे कोई कारण नहीं दिखता कि अवैध क्यों होना चाहिए; यदि आप बूल के साथ डायनामिक की जगह लेते हैं, तो यह ठीक है।

मैं कल C # टीम के साथ वास्तव में मिल रहा हूँ; मैं उनका उल्लेख करूंगा। त्रुटि के लिए क्षमा याचना!


6
मुझे यह जानकर खुशी हुई कि मैं पागल नहीं हो रहा हूँ :) मैंने तब से अपने कोड को अपडेट करने का प्रयास किया है केवल ट्रायपर्स पर भरोसा करने के लिए, इसलिए मैं अभी इसके लिए तैयार हूं। आपकी अंतर्दृष्टि के लिए धन्यवाद!
ब्रैंडन मार्टिनेज

4
@ नोमिनसिम: मान लीजिए कि रनटाइम विश्लेषण विफल हो जाता है: तो स्थानीय पढ़ने से पहले एक अपवाद फेंक दिया जाता है। मान लीजिए कि रनटाइम विश्लेषण सफल होता है: तो रनटाइम में या तो d सत्य है और y सेट है, या d गलत है और M सेट y है। किसी भी तरह, y सेट है। तथ्य यह है कि विश्लेषण तब तक स्थगित है जब तक कि रनटाइम कुछ भी नहीं बदलता है।
एरिक लिपर्ट

2
किसी के उत्सुक होने की स्थिति में: मैंने अभी जाँच की है, और मोनो कंपाइलर सही है। imgur.com/g47oquT
दान ताओ

17
मुझे लगता है कि संकलक व्यवहार वास्तव में सही है, क्योंकि dहो सकता है कि मूल्य एक अतिभारित trueऑपरेटर के साथ एक प्रकार का हो । मैंने एक उदाहरण के साथ एक उत्तर पोस्ट किया है जहां न तो शाखा ली जाती है।
क्वार्टरमेस्टर

2
@Quartermeister जिस मामले में मोनो संकलक गलत हो रहा है :)
7:56

52

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

||ऑपरेटर लागू करेगा trueदाएँ हाथ की ओर मूल्यांकन करने के लिए तय करने के लिए ऑपरेटर, और फिर ifबयान लागू करेगा trueउसके शरीर का मूल्यांकन करने के लिए कि क्या तय करने के लिए ऑपरेटर। एक सामान्य के लिए bool, ये हमेशा एक ही परिणाम लौटाएंगे और वास्तव में एक का मूल्यांकन किया जाएगा, लेकिन उपयोगकर्ता-परिभाषित ऑपरेटर के लिए ऐसी कोई गारंटी नहीं है!

एरिक लिपर्ट के रिप्रो के निर्माण, यहां एक छोटा और पूरा कार्यक्रम है जो एक ऐसे मामले को प्रदर्शित करता है जहां न तो पथ निष्पादित किया जाएगा और चर का प्रारंभिक मूल्य होगा:

using System;

class Program
{
    static bool M(out int x)
    {
        x = 123;
        return true;
    }

    static int N(dynamic d)
    {
        int y = 3;
        if (d || M(out y))
            y = 10;
        return y;
    }

    static void Main(string[] args)
    {
        var result = N(new EvilBool());
        // Prints 3!
        Console.WriteLine(result);
    }
}

class EvilBool
{
    private bool value;

    public static bool operator true(EvilBool b)
    {
        // Return true the first time this is called
        // and false the second time
        b.value = !b.value;
        return b.value;
    }

    public static bool operator false(EvilBool b)
    {
        throw new NotImplementedException();
    }
}

8
यहां अच्छा काम हुआ। मैंने इसे C # परीक्षण और डिजाइन टीमों के साथ पारित किया है; मैं देखूंगा कि क्या कल को उन्हें देखने पर उन पर कोई टिप्पणी होगी।
एरिक लिपर्ट

3
यह मेरे लिए बहुत अजीब है। dदो बार मूल्यांकन क्यों किया जाना चाहिए ? (मैं यह स्पष्ट नहीं कर रहा हूं कि यह स्पष्ट रूप से है , जैसा कि आपने दिखाया है।) मैंने कथन trueके पहले परिणाम (पहले संचालक आह्वान, कारण ||) के मूल्यांकन परिणाम की अपेक्षा की होगी if। उदाहरण के लिए, यदि आप फ़ंक्शन कॉल करते हैं तो निश्चित रूप से यह क्या होगा।
दान ताओ

3
@DanTao: अभिव्यक्ति dका मूल्यांकन केवल एक बार किया जाता है, जैसा कि आप उम्मीद करते हैं। यह वह trueऑपरेटर है जिसे दो बार, एक बार ||और एक बार द्वारा आमंत्रित किया जा रहा है if
क्वार्टरमेस्टर

2
@DanTao: यह अधिक स्पष्ट हो सकता है अगर हम उन्हें अलग-अलग बयानों के रूप में रखते हैं var cond = d || M(out y); if (cond) { ... }। पहले हम dएक EvilBoolवस्तु संदर्भ प्राप्त करने के लिए मूल्यांकन करते हैं । का मूल्यांकन करने के लिए ||, हम पहले EvilBool.trueउस संदर्भ के साथ आह्वान करते हैं। यह सच है, इसलिए हम शॉर्ट-सर्किट करते हैं और आह्वान नहीं करते हैं M, और फिर संदर्भ देते हैं cond। फिर, हम ifबयान पर जाते हैं। ifबयान को फोन करके इसकी हालत का मूल्यांकन करता है EvilBool.true
क्वार्टरमेस्टर

2
अब यह वास्तव में अच्छा है। मुझे नहीं पता था कि सच या गलत ऑपरेटर है।
इलिदान्स

7

MSDN से (जोर मेरा):

डायनेमिक टाइप उन ऑपरेशंस को सक्षम करता है जिसमें यह कंपाइल-टाइम टाइप चेकिंग को बायपास करता है । इसके बजाय, इन ऑपरेशन को रन टाइम पर हल किया जाता है । डायनामिक प्रकार COM APIs जैसे ऑफिस ऑटोमेशन API और आयरनपीथॉन लाइब्रेरीज़ जैसे डायनेमिक APIs और HTML डॉक्यूमेंट ऑब्जेक्ट मॉडल (DOM) तक पहुँच को सरल करता है।

टाइप डायनेमिक अधिकांश परिस्थितियों में टाइप ऑब्जेक्ट की तरह व्यवहार करता है। हालाँकि, ऐसे ऑपरेशन जिनमें टाइप डायनेमिक की अभिव्यक्तियाँ होती हैं, उन्हें हल नहीं किया जाता है या कंपाइलर द्वारा जाँच नहीं की जाती है।

चूंकि कंपाइलर किसी भी ऑपरेशन को टाइप या चेक नहीं करता है, जिसमें टाइप डायनेमिक की अभिव्यक्ति होती है, इसलिए यह आश्वासन नहीं दे सकता कि वेरिएबल को इस्तेमाल के जरिए सौंपा जाएगा TryParse()


यदि पहली शर्त पूरी हो जाती है, numberGroupsतो उसे ( if trueब्लॉक में) असाइन किया जाता है , यदि नहीं, तो दूसरी स्थिति असाइनमेंट (थ्रू out) की गारंटी देती है ।
लेपी

1
यह एक दिलचस्प विचार है, लेकिन कोड myString == null(केवल भरोसा करने के बिना) ठीक संकलन करता है TryParse
ब्रैंडन मार्टिनेज

1
@leppie बिंदु यह है कि चूंकि पहली स्थिति (वास्तव में संपूर्ण ifअभिव्यक्ति) में एक dynamicचर शामिल है , इसलिए इसे संकलन समय पर हल नहीं किया जाता है (इसलिए संकलक उन धारणाओं को नहीं बना सकता है)।
नोमिनसिम

@ नोमिनसिम: मैं आपकी बात देखता हूं :) +1 कंपाइलर (सी # नियम तोड़ने) से एक बलिदान हो सकता है, लेकिन अन्य सुझावों से लगता है कि यह एक बग है। एरिक का स्निपेट दिखाता है कि यह एक बलिदान नहीं है, बल्कि एक बग है।
लेप्पी

@NominSim यह सही नहीं हो सकता; सिर्फ इसलिए कि कुछ संकलक कार्य स्थगित हैं, इसका मतलब यह नहीं है कि वे सभी हैं। यह दिखाने के लिए बहुत सारे सबूत हैं कि थोड़ी अलग परिस्थितियों में, संकलक एक गतिशील अभिव्यक्ति की उपस्थिति के बावजूद, समस्या के बिना निश्चित असाइनमेंट विश्लेषण करता है।
18
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.