यह शून्य स्ट्रिंग्स को समाप्‍त करने के लिए वैध है, लेकिन "null.ToString ()" को कॉल करने के लिए नहीं?


126

यह मान्य सी # कोड है

var bob = "abc" + null + null + null + "123";  // abc123

यह C # कोड मान्य नहीं है

var wtf = null.ToString(); // compiler error

पहला बयान क्यों मान्य है?


97
मुझे यह अजीब लगता है कि आपका null.ToString()नाम दिया गया है wtf। क्यों आपको आश्चर्य होता है? जब आप इसके पास पहली जगह से कॉल करने के लिए कुछ नहीं है तो आप एक इंस्टेंस विधि नहीं कह सकते।
BoltClock

11
@BoltClock: बेशक यह एक अशक्त उदाहरण पर एक इंस्टेंस विधि को कॉल करना संभव है। सी # में संभव नहीं है, लेकिन सीएलआर पर बहुत वैध है :)
लेपी

1
String.Concat के संबंध में उत्तर लगभग सही हैं। वास्तव में, प्रश्न में विशिष्ट उदाहरण निरंतर तह में से एक है , और पहली पंक्ति में नल संकलक द्वारा समाप्त हो जाते हैं- अर्थात उन्हें रनटाइम पर कभी भी मूल्यांकन नहीं किया जाता है क्योंकि वे अब मौजूद नहीं हैं- संकलक ने उन्हें मिटा दिया है। मैंने अधिक जानकारी के लिए स्ट्रिंग्स के निरंतरता और निरंतर मोड़ के लिए सभी नियमों पर थोड़ा एकालाप लिखा: stackoverflow.com/questions/9132338/…
क्रिस शिन

77
आप एक स्ट्रिंग में कुछ भी नहीं जोड़ सकते हैं, लेकिन आप एक स्ट्रिंग को कुछ नहीं से बाहर कर सकते हैं।
आरजीबी

क्या दूसरा कथन मान्य नहीं है? class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
ctrl-alt-delor

जवाबों:


163

पहले काम करने का कारण:

से MSDN :

स्ट्रिंग संघनन कार्यों में, सी # संकलक एक रिक्त स्ट्रिंग के समान नल स्ट्रिंग का व्यवहार करता है, लेकिन यह मूल नल स्ट्रिंग के मूल्य को परिवर्तित नहीं करता है।

+ बाइनरी ऑपरेटर पर अधिक जानकारी :

जब एक या दोनों ऑपरेंड टाइप स्ट्रिंग के होते हैं, तो बाइनरी + ऑपरेटर स्ट्रिंग कॉन्फैनेटेशन करता है।

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

यदि ToStringरिटर्न null, एक खाली स्ट्रिंग प्रतिस्थापित किया जाता है।

दूसरे में त्रुटि का कारण है:

null (C # संदर्भ) - null कीवर्ड एक शाब्दिक है जो एक शून्य संदर्भ का प्रतिनिधित्व करता है, एक जो किसी भी वस्तु का संदर्भ नहीं देता है। नल संदर्भ-प्रकार चर का डिफ़ॉल्ट मान है।


1
क्या यह काम करेगा? var wtf = ((String)null).ToString();मैं हाल ही में जावा में काम कर रहा हूँ जहाँ null's कास्टिंग संभव है, जब से मैंने C # के साथ काम किया है तब से कुछ समय हो गया है।
जोकेम

14
@ जोकेम: आप अभी भी एक अशक्त वस्तु पर एक विधि को कॉल करने की कोशिश कर रहे हैं, इसलिए मैं अनुमान लगा रहा हूं कि नहीं। इसे null.ToString()बनाम के रूप में सोचो ToString(null)
Svish

@ हाँ, अब मैं इसे फिर से सोचता हूँ, यह एक अशक्त वस्तु है, इसलिए आप सही हैं, यह काम नहीं करेगा। यह जावा में नहीं होगा और न ही: शून्य सूचक अपवाद। कोई बात नहीं। आपके उत्तर के लिए tnx! [संपादित करें: जावा में इसका परीक्षण किया: NullPointerException। इस अंतर के साथ कि यह कलाकारों के साथ संकलित है, कलाकारों के बिना यह नहीं]।
जोकेम

आमतौर पर जानबूझकर संक्षिप्त या अशक्त कीवर्ड को हटाने का कोई कारण नहीं है। अगर आपको खाली स्ट्रिंग स्ट्रिंग की आवश्यकता है। अगर आपको यह जांचने की आवश्यकता है कि क्या स्ट्रिंग चर शून्य है या तो आप (myString == null) या string का उपयोग कर सकते हैं या string.IsNullOrEmpty (myString)। वैकल्पिक रूप से एक स्ट्रिंग स्ट्रिंग चर को स्ट्रिंग में बदलने के लिए। खाली उपयोग myNewString = (myString == null ?? string.Empty)
csauve

@ जोकेम कास्टिंग वह इसे संकलित करेगा लेकिन यह वास्तव में NullReferenceException को रनटाइम पर फेंक देगा
jeroenh

108

क्योंकि +C # में ऑपरेटर आंतरिक रूप से अनुवाद करता है String.Concat, जो एक स्थिर विधि है। और यह विधि nullएक खाली स्ट्रिंग की तरह व्यवहार करती है। यदि आप String.Concatरिफ्लेक्टर के स्रोत को देखते हैं, तो आप इसे देखेंगे:

// while looping through the parameters
strArray[i] = (str == null) ? Empty : str;
// then concatenate that string array

(MSDN ने इसका भी उल्लेख किया है: http://msdn.microsoft.com/en-us/library/k9c94ey1.aspx )

दूसरी ओर, ToString()एक उदाहरण विधि है, जिसे आप कॉल नहीं कर सकते हैं null(किस प्रकार का उपयोग किया जाना चाहिए null?)।


2
हालांकि स्ट्रिंग क्लास में कोई भी + ऑपरेटर नहीं है .. तो क्या यह String.Concat में अनुवाद करने वाला कंपाइलर है?
सुपरलॉजिकल

@ सुपरप्रयोगिकल यस, जो कंपाइलर करता है। तो वास्तव में, +सी # में स्ट्रिंग्स पर ऑपरेटर बस के लिए सिंथेटिक चीनी है String.Concat
बॉटज़ ३०००

इसके साथ जोड़ना: संकलक स्वचालित रूप से कॉनैट के अधिभार को उठाता है जो सबसे अधिक समझ में आता है। उपलब्ध अधिभार 1, 2 या 3 ऑब्जेक्ट पैरामीटर, 4 ऑब्जेक्ट पैरामीटर + __arglistऔर paramsऑब्जेक्ट एरे संस्करण हैं।
वर्म्बो

क्या स्ट्रिंग सरणी वहाँ संशोधित किया जा रहा है? है Concatहमेशा गैर-शून्य तार की एक नई सरणी यहाँ तक कि जब गैर-शून्य तार की एक सरणी दिया, या कुछ और चल रहा है बनाने के?
सुपरकैट

@supercat संशोधित सरणी एक नई सरणी है, जिसे बाद में एक निजी सहायक विधि के पास भेज दिया जाता है। आप स्वयं परावर्तक का उपयोग करके कोड को देख सकते हैं।
बॉटज़ ३०००

29

पहला नमूना में अनुवाद किया जाएगा:

var bob = String.Concat("abc123", null, null, null, "abs123");

Concatविधि चेकों इनपुट और एक खाली स्ट्रिंग के रूप में अशक्त का अनुवाद

दूसरा नमूना में अनुवाद किया जाएगा:

var wtf = ((object)null).ToString();

इसलिए यहां एक nullसंदर्भ अपवाद उत्पन्न होगा


दरअसल, एक AccessViolationExceptionफेंक दिया जाएगा :)
लेप्पी

मैंने अभी :) ((object)null).ToString()=> AccessViolation ((object)1 as string).ToString()=>NullReference
लेप्पी

1
मुझे NullReferenceException मिली है। DN 4.0
वायाचेस्लाव स्मितामुख

दिलचस्प। जब मैं ((object)null).ToString()अंदर डालता हूं तो मुझे भी try/catchमिलता NullReferenceExceptionहै।
लेप्पी

3
@ इप्पी सिवाय इसके कि एक्सेस वॉयलेशन को नहीं फेंकेगा (ऐसा क्यों होगा?) - NullReferenceException यहां।
jeroenh

11

आपके कोड का पहला भाग सिर्फ इस तरह से व्यवहार किया जाता है String.Concat,

जब आप तार जोड़ते हैं तो C # संकलक कॉल क्या होता है। "में abc" + nullअनुवादित हो जाता है String.Concat("abc", null),

और आंतरिक रूप से, वह तरीका बदल nullजाता है String.Empty। तो, इसीलिए आपके पहले भाग के कोड में कोई अपवाद नहीं है। यह वैसा ही है

var bob = "abc" + string.Empty + string.Empty + string.Empty + "123";  //abc123

और आपके कोड का दूसरा भाग अपवाद छोड़ देता है क्योंकि 'null' कोई ऑब्जेक्ट नहीं है, null कीवर्ड एक शाब्दिक है जो एक शून्य संदर्भ का प्रतिनिधित्व करता है, एक जो किसी भी ऑब्जेक्ट को संदर्भित नहीं करता है। नल संदर्भ-प्रकार चर का डिफ़ॉल्ट मान है।

और ' ToString()' एक ऐसी विधि है जिसे किसी वस्तु के उदाहरण से नहीं बल्कि किसी भी शाब्दिक रूप से कहा जा सकता है।


3
String.Emptyके बराबर नहीं है null। यह कुछ तरीकों की तरह ही व्यवहार किया जाता है String.Concat। उदाहरण के लिए, यदि आपके पास एक स्ट्रिंग वैरिएबल सेट है null, तो C # इसे प्रतिस्थापित नहीं करेगा String.Emptyयदि आप इस पर एक विधि को कॉल करने का प्रयास करते हैं।
बॉटज़ ३०००

3
लगभग। C # की nullतरह व्यवहार नहीं किया String.Emptyजाता है, यह उस तरह से व्यवहार किया जाता है, जैसा कि String.Concatआप तार जोड़ते समय C # संकलक कॉल करते हैं। आंतरिक रूप "abc" + nullसे अनुवाद किया जाता है String.Concat("abc", null), और यह विधि बदल जाती nullहै String.Empty। दूसरा भाग पूरी तरह से सही है।
बॉटज़ ३०००

9

COM फ्रेमवर्क में जो पूर्व में था .net, यह किसी भी दिनचर्या के लिए आवश्यक था जिसे इसे प्राप्त करने के लिए इसे मुक्त करने के लिए एक स्ट्रिंग प्राप्त हुई। चूँकि खाली तारों को रूटीन से बाहर और अंदर ले जाना बहुत आम बात थी, और क्योंकि एक अशक्त सूचक को "मुक्त" करने के प्रयास को एक वैध कार्य के रूप में परिभाषित नहीं किया गया था, इसलिए Microsoft ने यह सुनिश्चित करने का निर्णय लिया कि एक शून्य स्ट्रिंग पॉइंटर एक खाली स्ट्रिंग का प्रतिनिधित्व करता है।

COM के साथ कुछ संगतता के लिए अनुमति देने के लिए, नेट में कई रूटीन एक रिक्त स्ट्रिंग के रूप में एक कानूनी प्रतिनिधित्व के रूप में एक अशक्त वस्तु की व्याख्या करेगा। थोड़े से बदलाव के साथ .net और इसकी भाषाओं (विशेषकर उदाहरण के सदस्यों को "वर्चुअल के रूप में आह्वान नहीं करने के लिए संकेत देने की अनुमति"), Microsoft nullघोषित प्रकारों की वस्तुओं को बना सकता था स्ट्रिंग भी खाली स्ट्रिंग की तरह व्यवहार करते हैं। यदि Microsoft ने ऐसा किया होता, तो उसे Nullable<T>कुछ अलग तरीके से भी काम करना होता (ताकि अनुमति देने के लिए - Nullable<String>जैसा कि उन्हें IMHO को वैसे भी करना चाहिए था) और / या एक NullableStringप्रकार को परिभाषित करना जो ज्यादातर के साथ विनिमेय Stringहोगा, लेकिन जो एक संबंध नहीं होगा nullएक वैध खाली स्ट्रिंग के रूप में।

जैसा कि यह है, कुछ संदर्भ हैं जिनमें nullएक वैध खाली स्ट्रिंग के रूप में माना जाएगा और अन्य जिसमें यह नहीं होगा। बहुत उपयोगी स्थिति नहीं है, लेकिन प्रोग्रामर को कौन से बारे में पता होना चाहिए। सामान्य तौर पर, stringValue.someMemberयदि कोई stringValueहै तो फ़ॉर्म के भाव विफल हो जाएंगे null, लेकिन अधिकांश फ्रेमवर्क विधियां और ऑपरेटर जो स्ट्रिंग को पैरामीटर के रूप में स्वीकार करते हैं null, वे रिक्त स्ट्रिंग के रूप में मानेंगे।


5

'+'एक infix ऑपरेटर है। किसी भी ऑपरेटर की तरह यह वास्तव में एक तरीका है। आप एक गैर- infix संस्करण की कल्पना कर सकते हैं"wow".Plus(null) == "wow"

कार्यान्वयनकर्ता ने कुछ इस तरह का निर्णय लिया है ...

class String
{
  ...
  String Plus(ending)
  {
     if(ending == null) return this;
     ...
  }
} 

तो .. आपका उदाहरण बन जाता है

var bob = "abc".Plus(null).Plus(null).Plus(null).Plus("123");  // abc123

जो जैसा है वैसा है

var bob = "abc".Plus("123");  // abc123

किसी भी बिंदु पर अशक्त एक स्ट्रिंग नहीं बन जाता है। तो null.ToString()वह अलग नहीं है null.VoteMyAnswer()। ;)


वास्तव में, यह अधिक पसंद है var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");। ऑपरेटर ओवरलोड उनके दिल में स्थिर तरीके हैं: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx वे थे, var bob = null + "abc";या विशेष रूप string bob = null + null;से मान्य नहीं होंगे।
बेन मोजर

आप सही हैं, मुझे लगा कि अगर मैं इसे इस तरह समझाता हूं तो मुझे बहुत भ्रम होगा।
निगेल थॉर्न

3

मुझे लगता है क्योंकि यह एक शाब्दिक है जो किसी भी वस्तु को संदर्भित नहीं करता है। ToString()एक की जरूरत है object


3

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

var x = null + (string)null;     
var wtf = x.ToString();

ठीक काम करता है और एक अपवाद बिल्कुल नहीं फेंकता है। अंतर केवल इतना है कि आपको एक नल को स्ट्रिंग में डालने की आवश्यकता है - यदि आप (स्ट्रिंग) कास्ट निकालते हैं , तो उदाहरण अभी भी संकलित करता है, लेकिन एक रन-टाइम अपवाद को फेंकता है: "ऑपरेटर '+ ऑपरेंड पर अस्पष्ट है '<null>' और '<null>' टाइप करें।

NB ऊपर दिए गए कोड उदाहरण में, x का मान शून्य नहीं है जैसा कि आप उम्मीद कर सकते हैं, यह वास्तव में एक स्ट्रिंग को एक स्ट्रिंग में डालने के बाद एक खाली स्ट्रिंग है।


एक और दिलचस्प तथ्य यह है कि C # / .NET में में जिस तरह nullसे व्यवहार किया जाता है वह हमेशा समान नहीं होता है यदि आप विभिन्न डेटा प्रकारों का संबंध रखते हैं। उदाहरण के लिए:

int? x = 1;  //  string x = "1";
x = x + null + null;
Console.WriteLine((x==null) ? "<null>" : x.ToString());

कोड स्निपेट की पहली पंक्ति के बारे में: यदि xएक अशक्त पूर्णांक चर (यानी int?) मान है 1, तो आप परिणाम प्राप्त कर रहे हैं<null> वापस । यदि यह मान के साथ एक स्ट्रिंग (जैसा कि टिप्पणी में दिखाया गया है) है "1", तो आप "1"इसके बजाय वापस आ रहे हैं <null>

एनबी भी दिलचस्प: यदि आप var x = 1;पहली पंक्ति के लिए उपयोग कर रहे हैं , तो आपको एक रनटाइम त्रुटि मिल रही है। क्यों? क्योंकि असाइनमेंट चर xको डेटाटाइप में बदल देगा int, जो कि अशक्त नहीं है। कंपाइलर int?यहां नहीं मानता है, और इसलिए दूसरी पंक्ति में विफल रहता है जहां nullजोड़ा जाता है।


2

nullएक स्ट्रिंग को जोड़ना केवल अनदेखा किया जाता है। null(आपके दूसरे उदाहरण में) किसी भी वस्तु का उदाहरण नहीं है, इसलिए यह एक ToString()विधि भी नहीं है । यह सिर्फ एक शाब्दिक है।


1

क्योंकि जब string.Emptyऔर nullजब आप तार काटते हैं, तब कोई अंतर नहीं होता। आप अशक्त string.Formatरूप में अच्छी तरह से पास कर सकते हैं । लेकिन आप एक विधि को कॉल करने का प्रयास कर रहे हैं null, जिसके परिणामस्वरूप हमेशा परिणाम होगा NullReferenceExceptionऔर इसलिए एक कंपाइलर त्रुटि उत्पन्न होती है।
यदि किसी कारण से आप वास्तव में इसे करना चाहते हैं, तो आप एक विस्तार विधि लिख सकते हैं, जो जांचता है nullऔर फिर लौटता है string.Empty। लेकिन इस तरह के एक विस्तार का उपयोग केवल तभी किया जाना चाहिए जब पूरी तरह से आवश्यक हो (मेरी राय में)।


0

सामान्य रूप में: यह विनिर्देश के आधार पर एक पैरामीटर के रूप में नल को स्वीकार करने या मान्य नहीं हो सकता है, लेकिन यह हमेशा शून्य पर एक विधि को कॉल करने के लिए अमान्य है।


यह और अन्य विषय है कि तार के मामले में + ऑपरेटर के ऑपरेशन्स क्यों अशक्त हो सकते हैं। प्रोग्रामर के जीवन को आसान बनाने के लिए यह थोड़े वीबी (सॉरी लोग) है, या प्रोग्रामर को दबाने से अशक्तों से नहीं निपट सकते। मैं इस विनिर्देश से पूरी तरह असहमत हूं। 'अज्ञात' + 'कुछ भी' अभी भी 'अज्ञात' होना चाहिए ...

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