(यह == नल) C # में!


129

बग जो कि C # 4 में तय किया गया था, निम्नलिखित प्रोग्राम प्रिंट करता है true। (इसे LINQPad में आज़माएं)

void Main() { new Derived(); }

class Base {
    public Base(Func<string> valueMaker) { Console.WriteLine(valueMaker()); }
}
class Derived : Base {
    string CheckNull() { return "Am I null? " + (this == null); }
    public Derived() : base(() => CheckNull()) { }
}

VS2008 में रिलीज़ मोड में, यह एक InvalidProgramException फेंकता है। (डिबग मोड में, यह ठीक काम करता है)

VS2010 बीटा 2 में, यह संकलन नहीं करता है (मैंने बीटा 1 की कोशिश नहीं की); मैंने वह कठिन रास्ता सीख लिया

क्या this == nullशुद्ध C # बनाने का कोई और तरीका है ?


3
यह C # 3.0 कंपाइलर में बग की सबसे अधिक संभावना है। यह C # 4.0 में काम करना चाहिए।
मेहरदाद अफश्री

82
@SLaks: बग्स के साथ समस्या यह है कि आप उनसे कुछ बिंदु पर तय होने की उम्मीद कर सकते हैं, इसलिए उन्हें "उपयोगी" खोजना शायद बुद्धिमान नहीं है।
एंथनीवजोन

6
धन्यवाद! LINQPad के बारे में पता नहीं था। यह शान्त है!
कांटा

8
किस तरीके से, वास्तव में, क्या यह उपयोगी है?
एलन राइस

6
यह बग कैसे उपयोगी था?
ब्लैकटाइगर एक्स

जवाबों:


73

इस अवलोकन को आज एक अन्य प्रश्न में स्टैकऑवरफ्लो पर पोस्ट किया गया है।

उस सवाल का मार्क का शानदार जवाब बताता है कि युक्ति (खंड 7.5.7) के अनुसार, आपको thisउस संदर्भ में एक्सेस करने में सक्षम नहीं होना चाहिए और सी # 3.0 कंपाइलर में ऐसा करने की क्षमता एक बग है। सी # 4.0 कंपाइलर युक्ति के अनुसार सही व्यवहार कर रहा है (यहां तक ​​कि बीटा 1 में, यह एक संकलन समय त्रुटि है):

§ 7.5.7 यह एक्सेस

एक इस का उपयोग आरक्षित शब्द के होते हैं this

इस का उपयोग:

this

एक इस का उपयोग केवल में अनुमति दी है ब्लॉक एक उदाहरण निर्माता, एक उदाहरण विधि, या एक उदाहरण एक्सेसर की।


2
मैं नहीं देखता, क्यों इस प्रश्न में प्रस्तुत कोड में, कीवर्ड का उपयोग "यह" अमान्य है। विधि CheckNull एक सामान्य उदाहरण विधि, है nonstatic । "इस" का उपयोग करना इस तरह की विधि में 100% वैध है, और यहां तक ​​कि इसे शून्य से तुलना करना मान्य है। आधार इनिट लाइन में त्रुटि है: यह बेस ctor के पैरामीटर के रूप में इंस्टेंस-बाउंड डेलीगेट को पास करने का प्रयास है। यह संकलक में बग (अर्धचालक जांच का एक छेद) है: यह संभव नहीं होना चाहिए। : base(CheckNull())यदि आपको चेकनॉल स्थिर नहीं है, तो आपको लिखने की अनुमति नहीं है, और समान रूप से आपको एक उदाहरण-बद्ध लैम्बडा को इनलाइन करने में सक्षम नहीं होना चाहिए।
quetzalcoatl

4
@quetzalcoatl: thisमें CheckNullविधि कानूनी है। क्या कानूनी नहीं है निहित इस का उपयोग में () => CheckNull(), अनिवार्य रूप से () => this.CheckNull()है, जो बाहर चल रहा है ब्लॉक एक उदाहरण निर्माता के। मैं मानता हूं कि कल्पना का जो हिस्सा मैं उद्धृत करता हूं, वह ज्यादातर thisकीवर्ड की वाक्यगत वैधता पर केंद्रित होता है , और शायद एक अन्य भाग इस मुद्दे को अधिक सटीक रूप से संबोधित करता है, लेकिन कल्पना के इस हिस्से से वैचारिक रूप से भी एक्सट्रपलेट करना आसान है।
मेहरदाद अफश्री

2
क्षमा करें, मैं असहमत हूं। जबकि मुझे पता है कि (और ऊपर टिप्पणी में लिखा है) और आप यह भी जानते हैं कि - आपने अपने (स्वीकार किए गए) उत्तर में समस्या के वास्तविक कारण का उल्लेख नहीं किया है। जवाब स्वीकार किया जाता है - इसलिए प्रतीत होता है कि लेखक ने इसे पकड़ लिया। लेकिन मुझे संदेह है कि सभी पाठक पहली नजर में लांबड़ा बनाम स्टेटंबा-लंब्दा को पहचानने के लिए चमकीले और धाराप्रवाह के रूप में उतने ही उज्ज्वल और धाराप्रवाह होंगे कि 'यह' और उत्सर्जित आईएल के साथ समस्याएं :) यही कारण है कि मैंने अपने तीन सेंट जोड़े। इसके अलावा, मैं बाकी सब चीजों से सहमत हूं, जो आपके और अन्य लोगों द्वारा पाया गया, उनका विश्लेषण और वर्णन किया गया :)
quetzalcoatl

24

डीबग मोड बाइनरी के कच्चे विघटन (बिना किसी अनुकूलन के परावर्तक) है:

private class Derived : Program.Base
{
    // Methods
    public Derived()
    {
        base..ctor(new Func<string>(Program.Derived.<.ctor>b__0));
        return;
    }

    [CompilerGenerated]
    private static string <.ctor>b__0()
    {
        string CS$1$0000;
        CS$1$0000 = CS$1$0000.CheckNull();
    Label_0009:
        return CS$1$0000;
    }

    private string CheckNull()
    {
        string CS$1$0000;
        CS$1$0000 = "Am I null? " + ((bool) (this == null));
    Label_0017:
        return CS$1$0000;
    }
}

CompilerGenerated विधि समझ में नहीं आता है; यदि आप IL (नीचे) को देखते हैं, तो यह एक अशक्त स्ट्रिंग (!) पर विधि को बुला रहा है ।

   .locals init (
        [0] string CS$1$0000)
    L_0000: ldloc.0 
    L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
    L_0006: stloc.0 
    L_0007: br.s L_0009
    L_0009: ldloc.0 
    L_000a: ret 

रिलीज़ मोड में, स्थानीय चर दूर अनुकूलित किया जाता है, इसलिए यह स्टैक पर एक गैर-मौजूद चर को पुश करने का प्रयास करता है।

    L_0000: ldloc.0 
    L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
    L_0006: ret 

(रिफ्लेक्टर क्रैश होने पर इसे C # में बदल देता है)


संपादित करें : क्या कोई (एरिक लिपर्ट?) जानता है कि संकलक क्यों उत्सर्जित करता है ldloc?


11

मेरे पास वह है! (और प्रमाण भी मिला)

वैकल्पिक शब्द


2
देर हो चुकी थी, एक संकेत था जिसे मुझे कोडिंग बंद कर देना चाहिए :) क्या DLR सामान IIRC के साथ हमारी हैकिंग थी।
लेप्पी

जो भी 'यह' है, उसके लिए एक डिबगर विज़ुअलाइज़र (डेबगरडिसप्ले) बनाइए, और उस मूर्ख को बनाइए जो आप अशक्त हैं? : D सिर्फ

10

यह एक "बग" नहीं है। यह आप प्रकार प्रणाली का दुरुपयोग कर रहे हैं। आपको thisकिसी निर्माता के वर्तमान उदाहरण ( ) के संदर्भ में कभी भी पास नहीं करना चाहिए ।

मैं बेस क्लास कंस्ट्रक्टर के भीतर एक वर्चुअल विधि कहकर एक समान "बग" बना सकता था।

सिर्फ इसलिए कि आप कुछ बुरा कर सकते हैं इसका मतलब यह नहीं है कि जब आप इसके द्वारा बिट प्राप्त करते हैं तो यह एक बग है।


14
यह एक कंपाइलर बग है। यह अमान्य IL उत्पन्न करता है। (मेरा उत्तर पढ़ें)
SLaks

संदर्भ स्थिर है, इसलिए आपको उस चरण में इंस्टेंस विधि संदर्भ की अनुमति नहीं दी जानी चाहिए।
लेप्पी

10
@Will: यह एक कंपाइलर बग है। कंपाइलर को उस कोड स्निपेट के लिए वैध , सत्यापन योग्य कोड उत्पन्न करना चाहिए या त्रुटि संदेश को थूकना चाहिए। जब एक संकलक कल्पना के अनुसार व्यवहार नहीं करता है, तो यह छोटी गाड़ी है
मेहरदाद अफश्री

2
@ विल # 4: जब मैंने कोड लिखा था, तो मैंने निहितार्थ के बारे में नहीं सोचा था। मुझे केवल एहसास हुआ कि जब वीएस2010 में संकलन बंद हो गया तो इसका कोई मतलब नहीं था। -
एसएलके

3
वैसे, कंस्ट्रक्टर में वर्चुअल मेथड कॉल पूरी तरह से वैध ऑपरेशन है। यह सिर्फ अनुशंसित नहीं है। यह तार्किक आपदाओं में परिणाम हो सकता है लेकिन कभी नहीं InvalidProgramException
मेहरदाद अफश्री

3

मैं गलत हो सकता है, लेकिन मुझे पूरा यकीन है कि अगर आपकी वस्तु nullवहाँ है तो कभी भी ऐसा परिदृश्य नहीं होगा जहाँ thisलागू होता है।

उदाहरण के लिए, आप कैसे कॉल करेंगे CheckNull?

Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException

3
कंस्ट्रक्टर तर्क में एक लंबोदर में। पूरा कोड स्निपेट पढ़ें। (और यह कोशिश करो अगर तुम मुझ पर विश्वास नहीं करते हो)
एसएलके

मैं मानता हूँ कि मुझे याद है कि C ++ में कोई वस्तु कैसे याद आती है कि किसी वस्तु का उसके सन्दर्भ में संदर्भ नहीं है और मैं सोच रहा हूँ कि क्या (यह == अशक्त) परिदृश्य का उपयोग उन मामलों में किया जाता है या नहीं यह जाँचने के लिए कि क्या किसी विधि को कॉल किया गया था एक सूचक को "इस" को उजागर करने से पहले ऑब्जेक्ट के निर्माता से बनाया गया है। हालाँकि, जहाँ तक मुझे C # में पता है, वहाँ कोई भी ऐसा मामला नहीं होना चाहिए जहाँ "यह" कभी अशक्त हो, डिस्पोज़ल या अंतिम रूप देने के तरीकों में भी नहीं।
जिपरसन

मुझे लगता है कि मेरा विचार यह है कि thisकंप्यूटर प्रोग्रामिंग के "कोगिटो, एर्गो योग" की तरह - अशक्त होने की संभावना के पारस्परिक रूप से अनन्य है। इसलिए अभिव्यक्ति का उपयोग करने की आपकी इच्छा this == nullऔर कभी भी यह सच है कि मुझे पथभ्रष्ट कर देता है।
डैन ताओ

दूसरे शब्दों में: मैंने आपका कोड पढ़ा; मैं जो कह रहा हूं वह यह है कि मैं सवाल करता हूं कि आप पहली जगह में क्या हासिल करना चाहते थे।
डैन ताओ

यह कोड बस बग प्रदर्शित करता है, और, जैसा कि आपने बताया, बिलकुल बेकार है। वास्तविक उपयोगी कोड देखने के लिए, मेरा दूसरा उत्तर पढ़ें।
SLAKs

-1

यकीन नहीं होता कि यह वही है जो आप ढूंढ रहे हैं

    public static T CheckForNull<T>(object primary, T Default)
    {
        try
        {
            if (primary != null && !(primary is DBNull))
                return (T)Convert.ChangeType(primary, typeof(T));
            else if (Default.GetType() == typeof(T))
                return Default;
        }
        catch (Exception e)
        {
            throw new Exception("C:CFN.1 - " + e.Message + "Unexpected object type of " + primary.GetType().ToString() + " instead of " + typeof(T).ToString());
        }
        return default(T);
    }

उदाहरण: UserID = CheckForNull (Request.QueryString ["UserID"], 147);


13
आपने प्रश्न को पूरी तरह से गलत समझा।
SLaks

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