2010-03-08 18 views
23

पिछले अनुभव से मैं इस धारणा के तहत था कि यह एक पूर्ण उदाहरण पर एक्सटेंशन विधियों को कॉल करने के लिए पूरी तरह कानूनी है (हालांकि शायद सलाह नहीं दी जा सकती है)। तो सी # में, इस कोड को संकलित करता है तथा रन:यह एक्सटेंशन विधि VB.NET में NullReferenceException क्यों फेंकती है?

// code in static class 
static bool IsNull(this object obj) { 
    return obj == null; 
} 

// code elsewhere 
object x = null; 
bool exists = !x.IsNull(); 

हालांकि, मैं सिर्फ एक साथ उदाहरण के कोड का एक छोटा सूट मेरे विकास टीम के अन्य सदस्यों के लिए डाल दिया गया था (हम सिर्फ .NET 3.5 और मैंने करने के लिए उन्नत हमारे पास उपलब्ध नई सुविधाओं) में से कुछ पर लाने के लिए टीम उठने का कार्य सौंपा गया है, और मैंने लिखा मैं क्या सोचा केवल खोजने के लिए कि यह वास्तव में एक NullReferenceException फेंकता ऊपर कोड की VB.NET बराबर होती है, ।

' code in module ' 
<Extension()> _ 
Function IsNull(ByVal obj As Object) As Boolean 
    Return obj Is Nothing 
End Function 

' code elsewhere ' 
Dim exampleObject As Object = Nothing 
Dim exists As Boolean = Not exampleObject.IsNull() 

डिबगर वहीं बंद हो जाता है, के रूप में अगर मैं एक उदाहरण विधि बुलाया था: कोड मैंने लिखा इस थी। क्या मैं कुछ गलत कर रहा हूं (उदाहरण के लिए, क्या सी # और वीबी.नेट के बीच विस्तार विधि को परिभाषित करने के तरीके में कुछ सूक्ष्म अंतर है? क्या यह वास्तव में VB.NET में एक शून्य उदाहरण पर एक एक्सटेंशन विधि को कॉल करने के लिए कानूनी है, हालांकि यह सी # में कानूनी है? (मैंने सोचा होता तो यह एक नेट चीज के रूप में भाषा-विशिष्ट बात करने का विरोध किया था, लेकिन शायद मैं गलत था।)

किसी को भी मेरे लिए यह एक व्याख्या कर सकते हैं?

+1

IsNull विधि सिर्फ एक उदाहरण है या आप वास्तव में x.IsNull उपयोग करना चाहते हैं कर रहे हैं() 'एक्स इज नथिंग' या 'x == null' के बजाय? – jrummell

+0

@jrummell: यह सिर्फ एक उदाहरण है। जैसा कि मैंने उल्लेख किया है, मैं कुछ उदाहरण कोड लिख रहा था यह बताता हूं कि मेरे कुछ टीम सदस्यों के लिए विस्तार विधियां कैसे काम करती हैं। मैं इस विधि के लिए एक टिप्पणी शामिल करना चाहता हूं कि "आप वास्तव में विस्तार विधियों के साथ ऐसा कर सकते हैं, हालांकि मैं इसकी अनुशंसा नहीं करता हूं" - बस यह दिखाने के लिए कि कैसे एक विस्तार विधि वास्तव में एक स्थिर है (साझा किया गया है) तरीका। लेकिन फिर मैंने पाया कि मैं * वीबी में ऐसा नहीं कर सका, जिसने मुझे आश्चर्यचकित कर दिया। –

+1

जैसा पाया गया है, यह देर से बाध्यकारी के लिए समर्थन के कारण है ... जैसे आप (दान) मुझे एहसास नहीं हुआ कि वीबी के पास देर से बाध्यकारी के लिए ऐसा समर्थन था, मुझे लगता है कि यह वीबी 6 के साथ एक संगतता की बात है। थोड़ी सी तरफ के रूप में, यदि आप अन्य डेवलपर्स के लिए कुछ मानक/प्रशिक्षण निर्धारित करने की सोच रहे हैं तो आप विकल्प सख्त को जरूरी कर सकते हैं क्योंकि मुझे लगता है कि इससे कई संभावित समस्याएं उठने में मदद मिलती है। निश्चित रूप से वाईएमएमवी। –

उत्तर

13

आप ऑब्जेक्ट प्रकार को VB.NET में विस्तारित नहीं कर सकते हैं।

मुख्य रूप से, हम विस्तार के तरीकों किसी भी अभिव्यक्ति है कि स्थिर "ऑब्जेक्ट" के रूप में लिखा गया के बंद बुलाया जा करने की अनुमति नहीं है। एक्सटेंशन विधियों द्वारा तोड़ने से लिखे गए किसी भी मौजूदा देर से बाध्य कोड को रोकने के लिए यह आवश्यक था।

संदर्भ:

+0

आह, कुछ मतलब है कि ... हालांकि मैं लगातार नाराज कर रहा हूँ, लेकिन मतभेद/सी #/वीबी के बीच विसंगतियों। उन लिंक किए गए लेखों से लेने के लिए महत्वपूर्ण वाक्यांश है; । बहुत बढ़िया 8-) –

+0

"जब आप वस्तु निर्दिष्ट करते हैं, तो इसका मतलब है" कुछ भी * अन्य एक वस्तु से * ले "@roygbiv:। के रूप में कोई है जो VB.NET में भी अक्सर कोड ऐसा नहीं करता, मैं ईमानदारी से पता नहीं था देर से बाध्य विधि इस तरह के कॉल लिंक में चर्चा उन लोगों के रूप भी संभव थे। (मैं अनुमान लगाया है कि VB.NET के लेट बाइंडिंग क्षमताओं काफी छोटे थे।) तो धन्यवाद मुझे कुछ नया सिखाने के लिए है, और पहले मैं क्या सोचता पर हिट करने के लिए होने के लिए "सही" यहाँ का जवाब है –

+1

@DanTao:। मैं चाहता हूँ VB.NET एक 'System.Object' के रूप में एक चर घोषित करने की अनुमति होगी और यह एक वर्ग संदर्भ जिसका आधार प्रकार' होने की System.Object' होता है के रूप में बस से व्यवहार करते है , 'ऑब्जेक्ट' से जुड़े विशेष हैंडलिंग के बिना। – supercat

0

ऐसा लगता है समस्या यह है कि वस्तु अशक्त है। इसके अलावा, अगर आप निम्नलिखित की तरह कुछ की कोशिश, आप कह स्ट्रिंग IsNull

Dim exampleObject As Object = "Test" 
Dim text As String = exampleObject.IsNull() 

मुझे लगता है कि आप जो भी मान exampleObject में लगा रहे हैं कहा जाता है एक विस्तार विधि नहीं है कि एक अपवाद मिल जाएगा, ढांचा किस प्रकार जानता है यह है।

जवाब नीचे मामले System.Object बढ़ा दिया गया है के लिए विशिष्ट हो रहा है: मैं व्यक्तिगत रूप से वस्तु वर्ग पर एक्सटेंशन के तरीकों, VB में न सिर्फ लेकिन यह भी CSharp में

8

अद्यतन से बचने चाहते हैं। अन्य कक्षाओं को विस्तारित करते समय वीबी में NullReferenceException नहीं है।

यह व्यवहार कारण इस Connect issue में कहा गया है के लिए डिजाइन कर रहा है:

वीबी आप विस्तार तरीकों वस्तु पर परिभाषित कॉल करने के लिए अनुमति देता है, लेकिन केवल यदि चर स्थिर वस्तु के रूप में आपके द्वारा लिखा गया नहीं है।

कारण वीबी भी समर्थन करता है, देर से बाध्यकारी है, और अगर हम एक विस्तार विधि से आबद्ध करें जब आप एक चर वस्तु के रूप में घोषित बंद के लिए एक कॉल बनाने, तो यह ambigous किया जाए या नहीं आप कॉल करने के लिए कोशिश कर रहे हैं है एक एक्सटेंशन विधि या एक ही नाम के साथ एक अलग देर से विधि।

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

उदाहरण:

Imports System.Runtime.CompilerServices 

Module Extensions 
    <Extension()> _ 
    Public Function IsNull(ByVal obj As Object) As Boolean 
     Return obj Is Nothing 
    End Function 

    <Extension()> _ 
    Public Function IsNull(ByVal obj As A) As Boolean 
     Return obj Is Nothing 
    End Function 

    <Extension()> _ 
    Public Function IsNull(ByVal obj As String) As Boolean 
     Return obj Is Nothing 
    End Function 

End Module 

Class A 
End Class 

Module Module1 

    Sub Main() 
     ' works 
     Dim someString As String = Nothing 
     Dim isStringNull As Boolean = someString.IsNull() 

     ' works 
     Dim someA As A = Nothing 
     Dim isANull As Boolean = someA.IsNull() 

     Dim someObject As Object = Nothing 
     ' throws NullReferenceException 
     'Dim someObjectIsNull As Boolean = someObject.IsNull() 

     Dim anotherObject As Object = New Object 
     ' throws MissingMemberException 
     Dim anotherObjectIsNull As Boolean = anotherObject.IsNull() 
    End Sub 

End Module 

वास्तव में, वीबी संकलक एक लेट बाइंडिंग कॉल मामले में अपने चर स्थिर Object के रूप में लिखा गया हो बनाता है:

.locals init ([0] object exampleObject, [1] bool exists) 
    IL_0000: ldnull 
    IL_0001: stloc.0 
    IL_0002: ldloc.0 
    IL_0003: ldnull 
    IL_0004: ldstr  "IsNull" 
    IL_0009: ldc.i4.0 
    IL_000a: newarr  [mscorlib]System.Object 
    IL_000f: ldnull 
    IL_0010: ldnull 
    IL_0011: ldnull 
    IL_0012: call  
    object [Microsoft.VisualBasic]Microsoft.VisualBasic. 
     CompilerServices.NewLateBinding::LateGet(
     object, 
     class [mscorlib]System.Type, 
     string, 
     object[], 
     string[], 
     class [mscorlib]System.Type[], 
     bool[]) 
    IL_0017: call  object [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::NotObject(object) 
    IL_001c: call  bool [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Conversions::ToBoolean(object) 
    IL_0021: stloc.1 
+0

मुझे आश्चर्य है - क्या वी # कॉल एक्सटेंशन विधियों को सी # तरीके से करता है यदि वे सी # में लिखी गई लाइब्रेरी में हैं? –

+0

और @ जोएल: मैंने अभी इसका परीक्षण किया - विस्तार विधि को सी # लाइब्रेरी में रखा, जिसे इसे वीबी से बुलाया गया। वीबी कोड ने अभी भी 'NullReferenceException' फेंक दिया है। ऐसा लगता है कि गैरेथ कुछ पर है: यह समस्या केवल तब मौजूद है जब एक्सटेंशन विधि 'System.Object' पर लागू होती है क्योंकि कुछ और विशिष्ट के विपरीत। –

+0

दरअसल, यह उस ऑब्जेक्ट का प्रकार है जिसे आप एक्सटेंशन विधि को कॉल करने का प्रयास कर रहे हैं, न कि फ़ंक्शन की अपेक्षा की जाती है। यही है, IsNull (ऑब्जेक्ट के रूप में ByVal Obj) Dim A As String के साथ काम करता है ... A.IsNull बस ठीक है, यहां तक ​​कि जहां ए कुछ भी नहीं है। ऐसा लगता है कि रॉयबिव के पास प्रासंगिक लिंक क्यों हैं। –

3

यह साथ कुछ विचित्र प्रतीत हो रहा है वस्तु, संभावित रूप से वीबी में एक बग या कंपाइलर में एक सीमा, टिप्पणी करने के लिए परम पावन जॉन स्कीट की आवश्यकता हो सकती है!

असल में ऐसा लगता है कि एक्सटेंशन विधि को कॉल करने के बजाय रनटाइम पर IsNull कॉल को देर से बांधने का प्रयास किया जा रहा है, जो NullReferenceException का कारण बनता है। यदि आप विकल्प सख्त चालू करते हैं तो आप इसे डिज़ाइन समय पर लाल squiggles के साथ देखेंगे।

उदाहरण बदलना ऑब्जेक्ट के अलावा किसी अन्य चीज़ के लिए अपने नमूना कोड को काम करने की अनुमति देगा, भले ही कहा गया प्रकार का मूल्य कुछ भी न हो।

+0

+1। एक्सटेंशन विधि ऑब्जेक्ट नहीं होने पर केवल कुछ भी उपयोग नहीं करने की अनुमति देती है। तो, यह रनटाइम पर ऑब्जेक्ट की प्रकृति से जुड़ा हुआ प्रतीत होता है। –

+0

हा, वाह ... अब यह अजीब है। –

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