2010-04-24 11 views
7

दूसरा संदर्भ एक्वाल्स कॉल झूठा रिटर्न देता है। एस 4 में स्ट्रिंग क्यों नहीं है? (मैं स्ट्रिंग संयोजन से अधिक StringBuilder के फायदे के बारे में परवाह नहीं है।)स्ट्रिंग इंटर्निंग?

string s1 = "tom"; 
string s2 = "tom"; 


Console.Write(object.ReferenceEquals(s2, s1)); //true 

string s3 = "tom"; 
string s4 = "to"; 
s4 += "m"; 

Console.Write(object.ReferenceEquals(s3, s4)); //false 

जब मैं String.Intern(s4); करते हैं, मैं अभी भी झूठी मिलता है।

यहां, दोनों एस 3 और एस 4 इंटर्न किए गए हैं लेकिन उनके संदर्भ बराबर नहीं हैं?

string s3 = "tom"; 
string s4 = "to"; 
s4 += "m"; 
String.Intern(s4); 

Console.WriteLine(s3 == s4); //true 
Console.WriteLine(object.ReferenceEquals(s3, s4)); //false 
Console.WriteLine(string.IsInterned(s3) != null); //true (s3 is interned) 
Console.WriteLine(string.IsInterned(s4) != null); //true (s4 is interned) 
+0

कृपया, एस 4 = स्ट्रिंग के साथ एक और समय सत्यापित करें। इंटरनेट (एस 4); कंसोल। राइट (ऑब्जेक्ट। रेफरेंस एक्वाल्स (एस 3, एस 4)); यह .NET 2.0,3.0,3.5,4.0 के लिए सच है। इसके अलावा, यदि आप s3 = स्ट्रिंग का परीक्षण करते हैं। इंटरनेट (एस 3); कंसोल। राइट (ऑब्जेक्ट। रेफरेंस एक्वाल्स (एस 3, एस 1)); आप देख सकते हैं कि s3 = स्ट्रिंग। इंटरनेट (एस 3); कुछ भी नहीं करें क्योंकि स्कॉट डोर्मन ने सही लिखा है, एस 1 से एस 3 तक सभी पहले से ही इंटरैड किए गए हैं और एस 4 = स्ट्रिंग के साथ इसे बदलने से पहले केवल एक अद्वितीय ढेर पॉइंटर पर एस 4 पॉइंट हैं। इंटरनेशनल (एस 4); – Oleg

+0

string.Interned() का मतलब यह नहीं है कि पारित स्ट्रिंग ऑब्जेक्ट को एक इंटर्न वाली स्ट्रिंग के रूप में बनाया गया था, इसका मतलब है कि इंटर्न वाले स्टोर में एक ही मूल्य है। उलझन में, हुह! –

+0

समझ में आता है। लेकिन स्ट्रिंग। इंटरनेशनल (एस 4) तब स्ट्रिंग को इंटर्न नहीं करता है? – rkrauter

उत्तर

16

s4 में स्ट्रिंग को प्रशिक्षित किया गया है। हालांकि, जब आप s4 += "m"; निष्पादित करते हैं, तो आपने एक नई स्ट्रिंग बनाई है जिसे इंटर्न नहीं किया जाएगा क्योंकि इसका मान स्ट्रिंग अक्षर नहीं है बल्कि एक स्ट्रिंग कॉन्सटेनेशन ऑपरेशन का परिणाम है। नतीजतन, s3 और s4 दो अलग-अलग मेमोरी स्थानों में दो अलग-अलग स्ट्रिंग उदाहरण हैं।

स्ट्रिंग इंटर्निंग पर अधिक जानकारी के लिए, विशेष रूप से अंतिम उदाहरण पर here देखें। जब आप String.Intern(s4) करते हैं, तो आप वास्तव में स्ट्रिंग को इंटर्न कर रहे हैं, लेकिन आप अभी भी उन दो आंतरिक तारों के बीच एक संदर्भ समानता परीक्षण नहीं कर रहे हैं। String.Intern विधि प्रशिक्षु स्ट्रिंग देता है, तो आप ऐसा करने की आवश्यकता होगी:

string s1 = "tom"; 
string s2 = "tom"; 

Console.Write(object.ReferenceEquals(s2, s1)); //true 

string s3 = "tom"; 
string s4 = "to"; 
s4 += "m"; 

Console.Write(object.ReferenceEquals(s3, s4)); //false 

string s5 = String.Intern(s4); 

Console.Write(object.ReferenceEquals(s3, s5)); //true 
+0

उत्तर के रूप में चिह्नित किया गया धन्यवाद। अभी भी अजीब सामान।मैं इसे एस 4 के लिए बताता हूं और यह पूल में पहले से ही प्रशिक्षित स्ट्रिंग का संदर्भ देता है। जबकि गरीब एस 4 ढेर में एक गैर इंटर्न वाली स्ट्रिंग के रूप में बस लटकता है। – rkrauter

+0

धन्यवाद। यह एक संदर्भ देता है, लेकिन यदि तर्क के रूप में पारित स्ट्रिंग मान पहले से ही इंटर्न नहीं किया गया है, तो इसे प्रशिक्षित किया जाएगा और फिर संदर्भ वापस कर दिया जाएगा। स्ट्रिंग इंटर्निंग वास्तव में एक अनुकूलन तकनीक है जो मुख्य रूप से संकलक द्वारा उपयोग की जाती है ताकि एप्लिकेशन में स्ट्रिंग इंस्टेंस की संख्या कम हो सके। जब तक आप स्ट्रिंग के ** ** बहुत कुछ नहीं बना रहे हैं, तो शायद आपको इसे स्वयं करने में बहुत अधिक लाभ दिखाई नहीं देगा। –

3

स्ट्रिंग्स अपरिवर्तनीय हैं। इसका मतलब है कि उनकी सामग्री को बदला नहीं जा सकता है।

जब आप आंतरिक रूप से s4 += "m"; करते हैं, तो सीएलआर स्ट्रिंग को स्मृति में किसी अन्य स्थान पर कॉपी करता है जिसमें मूल स्ट्रिंग और संलग्न भाग होता है।

MSDN string reference देखें।

+0

मुझे लगता है कि तार अपरिवर्तनीय हैं। लेकिन इंटर्निंग का पूरा बिंदु स्मृति को सही तरीके से सहेजना है? सीएलआर क्यों नहीं कह सकता है, हे मेरे पास मेरे इंटर्न पूल में वही मूल्य है, मैं बस इसे इंगित करने जा रहा हूं। – rkrauter

+7

@rkrauter: इंटर्न पूल में सभी तारों की जांच करना काफी महंगा है चाहे उनमें से कोई भी ऑपरेशन के परिणाम के बराबर है - प्रत्येक ऑपरेशन के बाद! तो सीएलआर निष्पादन गति के लिए स्मृति दक्षता बलिदान। संकलन समय पर स्ट्रिंग गणना धीमी हो सकती है, इसलिए इसके परिणाम इंटर्न किए जा सकते हैं। रनटाइम पर गणना तेज होनी चाहिए, इसलिए अन्य स्ट्रिंग्स की श्रृंखला के विरुद्ध प्रत्येक परिणाम की जांच करना अव्यवहारिक प्रतीत होता है। – Vlad

+0

तो स्ट्रिंग इंटर्निंग मुख्य रूप से संकलन समय पर किया जाता है? बस ध्यान दिया कि जब मैं स्ट्रिंग करता हूं। आंतरिक (एस 4) ;, मुझे अभी भी झूठा लगता है। कृपया समझाएँ। – rkrauter

1

सी # में, प्रत्येक स्ट्रिंग एक अलग वस्तु है, और संपादित नहीं किया जा सकता है। आप उनके लिए संदर्भ बना रहे हैं, लेकिन प्रत्येक स्ट्रिंग अलग है। व्यवहार सुसंगत और समझने में आसान है।

क्या मैं StringBuilder कक्षा की जांच कर सकता हूं ताकि नए उदाहरण बनाये बिना स्ट्रिंग में हेरफेर किया जा सके? यह तारों के साथ आप जो भी करना चाहते हैं उसके लिए पर्याप्त होना चाहिए।

+1

यदि आप बड़े तारों को एक साथ जोड़ना चाहते हैं तो केवल एक स्ट्रिंगबिल्डर का उपयोग करें। अन्य सभी मामलों में बचाया गया समय इतना छोटा है, इससे कोई फर्क नहीं पड़ता। इसके अलावा, तारों को आंतरिक रूप से पहले से बनाए गए तारों की एक सरणी में रखा जाता है, इसका मतलब है, यदि आप स्ट्रिंग "हैलो" बनाते हैं, तो कोई और स्ट्रिंग "हैलो" स्मृति में एक ही संदर्भ को इंगित करेगी। – Femaref

2

सबसे पहले, अपरिवर्तनीय तारों के बारे में अब तक जो कुछ भी लिखा गया है वह सही है। लेकिन कुछ महत्वपूर्ण चीजें हैं जो लिखी नहीं गई हैं। कोड

string s1 = "tom"; 
string s2 = "tom"; 
Console.Write(object.ReferenceEquals(s2, s1)); //true 

प्रदर्शन वास्तव में "सही" है, लेकिन केवल कुछ छोटे संकलक अनुकूलन की वजह से या यहाँ की तरह है क्योंकि CLR उपेक्षा सी # संकलक गुण (देखें "के माध्यम से CLR सी #" किताब) और जगह ढेर में केवल एक स्ट्रिंग "tom" । आंतरिक हैश तालिका में एक ही हैश के लिए खोज

s3 = String.Intern(s3); 
s4 = String.Intern(s4); 
Console.Write (object.ReferenceEquals (s3, s4)); //true 

समारोह String.Intern तार का एक हैश कोड गणना करता है और:

दूसरा आप निम्नलिखित लाइनों के साथ स्थिति को ठीक कर सकते हैं। क्योंकि यह इसे पाता है, यह पहले से मौजूद String ऑब्जेक्ट के संदर्भ को वापस देता है। यदि स्ट्रिंग आंतरिक हैश तालिका में मौजूद नहीं है, तो स्ट्रिंग की एक प्रति बनाई गई है और हैश गणना की गई है। कचरा कलेक्टर स्ट्रिंग के लिए स्मृति मुक्त नहीं करता है, क्योंकि इसे हैश टेबल द्वारा संदर्भित किया जाता है।

1

स्रोत: https://blogs.msdn.microsoft.com/ericlippert/2009/09/28/string-interning-and-string-empty/

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

मैं सी # पृष्ठभूमि से हूँ, तो मैं उस से एक उदाहरण देकर समझाना कर सकते हैं:

निम्नलिखित तुलना की
object obj = "Int32"; 
string str1 = "Int32"; 
string str2 = typeof(int).Name; 

उत्पादन:

Console.WriteLine(obj == str1); // true 
Console.WriteLine(str1 == str2); // true  
Console.WriteLine(obj == str2); // false !? 

Note1: वस्तुओं संदर्भ द्वारा तुलना की जाती है ।

नोट 2: टाइपऑफ (int) .नाम का प्रतिबिंब विधि द्वारा मूल्यांकन किया जाता है, इसलिए इसे संकलन समय पर मूल्यांकन नहीं किया जाता है। यहां ये तुलना संकलन समय पर की जाती हैं।

के परिणाम विश्लेषण: 1) सच है क्योंकि वे दोनों एक ही शाब्दिक और होती है, इसलिए उत्पन्न केवल एक ही वस्तु को संदर्भित "Int32" होगा कोड। नोट 1 देखें।

2) सच है क्योंकि दोनों मानों की सामग्री की जांच की जाती है जो समान है।

3) गलत क्योंकि स्ट्र 2 और ओबीजे में एक ही शाब्दिक नहीं है। नोट 2 देखें।

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

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