Database
 sql >> डेटाबेस >  >> RDS >> Database

.NET में स्ट्रिंग्स के पहलू

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

मेमोरी में स्ट्रिंग्स का प्रतिनिधित्व

.Net में, स्ट्रिंग्स BSTR (बेसिक स्ट्रिंग या बाइनरी स्ट्रिंग) नियम के अनुसार स्थित होती हैं। स्ट्रिंग डेटा प्रतिनिधित्व की इस पद्धति का उपयोग COM में किया जाता है (शब्द 'बेसिक' विज़ुअल बेसिक प्रोग्रामिंग भाषा से उत्पन्न होता है जिसमें इसे शुरू में इस्तेमाल किया गया था)। जैसा कि हम जानते हैं, PWSZ (पॉइंटर टू वाइड-कैरेक्टर स्ट्रिंग, जीरो-टर्मिनेटेड) का उपयोग स्ट्रिंग्स के प्रतिनिधित्व के लिए C/C++ में किया जाता है। स्मृति में इस तरह के स्थान के साथ, एक स्ट्रिंग के अंत में एक नल-टर्मिनेटेड स्थित होता है। यह टर्मिनेटर स्ट्रिंग के अंत को निर्धारित करने की अनुमति देता है। PWSZ में स्ट्रिंग की लंबाई केवल खाली स्थान की मात्रा द्वारा सीमित है।

BSTR में, स्थिति थोड़ी अलग है।

स्मृति में BSTR स्ट्रिंग प्रतिनिधित्व के मूल पहलू निम्नलिखित हैं:

  1. स्ट्रिंग की लंबाई एक निश्चित संख्या द्वारा सीमित है। PWSZ में, स्ट्रिंग की लंबाई मुफ्त मेमोरी की उपलब्धता से सीमित होती है।
  2. BSTR स्ट्रिंग हमेशा बफ़र में पहले वर्ण की ओर इशारा करती है। PWSZ बफ़र में किसी भी वर्ण को इंगित कर सकता है।
  3. BSTR में, PWSZ के समान, शून्य वर्ण हमेशा अंत में स्थित होता है। BSTR में, शून्य वर्ण एक मान्य वर्ण है और इसे स्ट्रिंग में कहीं भी पाया जा सकता है।
  4. चूंकि नल टर्मिनेटर अंत में स्थित है, BSTR PWSZ के साथ संगत है, लेकिन इसके विपरीत नहीं।

इसलिए, .NET में स्ट्रिंग्स को BSTR नियम के अनुसार मेमोरी में दर्शाया जाता है। बफर में एक 4-बाइट स्ट्रिंग लंबाई होती है जिसके बाद UTF-16 प्रारूप में एक स्ट्रिंग के दो-बाइट वर्ण होते हैं, जो बदले में, दो नल बाइट्स (\u0000) द्वारा पीछा किया जाता है।

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

स्ट्रिंग ऑब्जेक्ट कितनी मेमोरी लेता है?

मुझे यह बताते हुए लेखों का सामना करना पड़ा कि स्ट्रिंग ऑब्जेक्ट का आकार आकार =20 + (लंबाई/2) * 4 के बराबर है, लेकिन यह सूत्र बिल्कुल सही नहीं है।

शुरू करने के लिए, एक स्ट्रिंग एक लिंक प्रकार है, इसलिए पहले चार बाइट्स में SyncBlockIndex . होता है और अगले चार बाइट्स में टाइप पॉइंटर होता है।

स्ट्रिंग का आकार =4 + 4 + …

जैसा कि मैंने ऊपर कहा, स्ट्रिंग की लंबाई बफर में जमा हो जाती है। यह एक इंट टाइप फील्ड है, इसलिए हमें और 4 बाइट्स जोड़ने की जरूरत है।

स्ट्रिंग का आकार =4 + 4 + 4 + …

एक स्ट्रिंग को मूल कोड पर जल्दी से (प्रतिलिपि किए बिना) पास करने के लिए, नल टर्मिनेटर प्रत्येक स्ट्रिंग के अंत में स्थित होता है जो 2 बाइट्स लेता है। इसलिए,

स्ट्रिंग का आकार =4 + 4 + 4 + 2 + …

केवल एक चीज बची है, यह याद रखना है कि एक स्ट्रिंग में प्रत्येक वर्ण UTF-16 कोडिंग में है और 2 बाइट्स भी लेता है। इसलिए:

स्ट्रिंग का आकार =4 + 4 + 4 + 2 + 2 * लंबाई =14 + 2 * लंबाई

एक और बात और हम कर चुके हैं। सीएलआर में मेमोरी मैनेजर द्वारा आवंटित मेमोरी 4 बाइट्स (4, 8, 12, 16, 20, 24, ...) का गुणक है। इसलिए, यदि स्ट्रिंग की लंबाई कुल 34 बाइट्स लेती है, तो 36 बाइट्स आवंटित किए जाएंगे। हमें अपने मान को निकटतम बड़ी संख्या में गोल करना होगा जो कि चार का गुणक हो। इसके लिए हमें चाहिए:

स्ट्रिंग आकार =4 * ((14 + 2 * लंबाई + 3) / 4) (पूर्णांक विभाजन)

संस्करणों का मुद्दा :.NET v4 तक, एक अतिरिक्त m_arrayLength . था स्ट्रिंग वर्ग में int प्रकार का क्षेत्र जिसमें 4 बाइट लगे। यह फ़ील्ड एक स्ट्रिंग के लिए आवंटित बफर की वास्तविक लंबाई है, जिसमें नल टर्मिनेटर भी शामिल है, यानी यह लंबाई + 1 है। .NET 4.0 में, इस फ़ील्ड को कक्षा से हटा दिया गया था। नतीजतन, एक स्ट्रिंग प्रकार की वस्तु 4 बाइट्स कम लेती है।

m_arrayLength . के बिना एक खाली स्ट्रिंग का आकार फ़ील्ड (यानी .Net 4.0 और उच्चतर में) =4 + 4 + 4 + 2 =14 बाइट्स के बराबर होता है, और इस फ़ील्ड के साथ (यानी .Net 4.0 से कम), इसका आकार बराबर होता है =4 + 4 + 4 + 4 + 2 =18 बाइट्स। अगर हम 4 बाइट्स का चक्कर लगाते हैं, तो आकार 16 और 20 बाइट्स का होगा।

स्ट्रिंग पहलू

इसलिए, हमने स्ट्रिंग्स के प्रतिनिधित्व और उनके द्वारा स्मृति में लिए गए आकार पर विचार किया। अब, उनकी ख़ासियतों के बारे में बात करते हैं।

.NET में स्ट्रिंग्स के मूल पहलू निम्नलिखित हैं:

  1. स्ट्रिंग संदर्भ प्रकार हैं।
  2. स्ट्रिंग अपरिवर्तनीय हैं। एक बार बनाने के बाद, एक स्ट्रिंग को संशोधित नहीं किया जा सकता है (उचित माध्यम से)। इस वर्ग की विधि की प्रत्येक कॉल एक नई स्ट्रिंग लौटाती है, जबकि पिछली स्ट्रिंग कचरा संग्रहकर्ता के लिए शिकार बन जाती है।
  3. स्ट्रिंग्स Object.Equalsविधि को फिर से परिभाषित करती हैं। परिणामस्वरूप, विधि स्ट्रिंग में वर्ण मानों की तुलना करती है, लिंक मानों की नहीं।

आइए प्रत्येक बिंदु पर विस्तार से विचार करें।

स्ट्रिंग संदर्भ प्रकार हैं

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

स्ट्रिंग अपरिवर्तनीय हैं

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

डेटा संरचनाओं को दो प्रकारों में विभाजित किया जा सकता है:अल्पकालिक और लगातार। अल्पकालिक डेटा संरचनाएं केवल उनके अंतिम संस्करणों को संग्रहीत करती हैं। लगातार डेटा संरचनाएं संशोधन के दौरान अपने सभी पिछले संस्करणों को सहेजती हैं। उत्तरार्द्ध, वास्तव में, अपरिवर्तनीय हैं, क्योंकि उनके संचालन साइट पर संरचना को संशोधित नहीं करते हैं। इसके बजाय, वे एक नई संरचना लौटाते हैं जो पिछले वाले पर आधारित होती है।

इस तथ्य को देखते हुए कि तार अपरिवर्तनीय हैं, वे लगातार हो सकते हैं, लेकिन वे नहीं हैं। स्ट्रिंग्स .Net में अल्पकालिक हैं।

तुलना के लिए, आइए जावा स्ट्रिंग्स लें। वे अपरिवर्तनीय हैं, जैसे .NET में, लेकिन साथ ही वे लगातार बने रहते हैं। जावा में स्ट्रिंग क्लास का कार्यान्वयन इस प्रकार दिखता है:

public final class String
	{
	    private final char value[];
	    private final int offset;
 	private final int count;
 	private int hash; 
  	.....
	}

ऑब्जेक्ट के हेडर में 8 बाइट्स के अलावा, टाइप के संदर्भ और सिंक्रोनाइज़ेशन ऑब्जेक्ट के संदर्भ सहित, स्ट्रिंग्स में निम्नलिखित फ़ील्ड होते हैं:

  1. चार सरणी का संदर्भ;
  2. चार सरणी में स्ट्रिंग के पहले वर्ण की अनुक्रमणिका (शुरुआत से ऑफ़सेट)
  3. स्ट्रिंग में वर्णों की संख्या;
  4. हैश कोड की गणना सबसे पहले HashCode() . पर कॉल करने के बाद की जाती है विधि।

जावा में स्ट्रिंग्स .NET की तुलना में अधिक मेमोरी लेती हैं, क्योंकि उनमें अतिरिक्त फ़ील्ड होते हैं जो उन्हें लगातार बने रहने की अनुमति देते हैं। दृढ़ता के कारण, String.substring() . का निष्पादन जावा में विधि O(1) takes लेती है , क्योंकि इसमें .NET की तरह स्ट्रिंग कॉपी करने की आवश्यकता नहीं होती है, जहां इस पद्धति का निष्पादन O(n) लेता है। ।

जावा में String.substring() विधि का कार्यान्वयन:

public String substring(int beginIndex, int endIndex) 
{
 if (beginIndex < 0) throw new StringIndexOutOfBoundsException(beginIndex); if (endIndex > count)
   throw new StringIndexOutOfBoundsException(endIndex);
 if (beginIndex > endIndex)
   throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
 return ((beginIndex == 0) && (endIndex == count)) ? this : new String(offset + beginIndex, endIndex - beginIndex, value);
}

public String(int offset, int count, char value[]) 
{
 this.value = value;
 this.offset = offset;
 this.count = count;
}

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

s =ss.substring(3)

निम्नलिखित कोड का उपयोग किया जा सकता है:

s =नया String(ss.substring(3)),

यह कोड स्रोत स्ट्रिंग के वर्णों की सरणी के संदर्भ को संग्रहीत नहीं करेगा। इसके बजाय, यह केवल सरणी के वास्तव में उपयोग किए गए भाग की प्रतिलिपि बनाएगा। वैसे, अगर हम इस कंस्ट्रक्टर को एक स्ट्रिंग पर कॉल करते हैं जिसकी लंबाई वर्णों की सरणी की लंबाई के बराबर होती है, तो कॉपी नहीं होगी। इसके बजाय, मूल सरणी के संदर्भ का उपयोग किया जाएगा।

जैसा कि यह निकला, जावा के अंतिम संस्करण में स्ट्रिंग प्रकार के कार्यान्वयन को बदल दिया गया है। अब, कक्षा में कोई ऑफसेट और लंबाई फ़ील्ड नहीं हैं। नया हैश32 (विभिन्न हैशिंग एल्गोरिदम के साथ) इसके बजाय पेश किया गया है। इसका मतलब है कि तार अब स्थिर नहीं हैं। अब, String.substring विधि हर बार एक नई स्ट्रिंग बनाएगी।

स्ट्रिंग Onbject.Equals को फिर से परिभाषित करें

स्ट्रिंग वर्ग Object.Equals विधि को फिर से परिभाषित करता है। नतीजतन, तुलना होती है, लेकिन संदर्भ से नहीं, बल्कि मूल्य से। मुझे लगता है कि डेवलपर्स ==ऑपरेटर को फिर से परिभाषित करने के लिए स्ट्रिंग क्लास के रचनाकारों के आभारी हैं, क्योंकि कोड जो स्ट्रिंग तुलना के लिए ==का उपयोग करता है वह विधि कॉल की तुलना में अधिक गहरा दिखता है।

if (s1 == s2)

की तुलना में

if (s1.Equals(s2))

वैसे, जावा में, ==ऑपरेटर संदर्भ द्वारा तुलना करता है। यदि आपको वर्ण के आधार पर स्ट्रिंग की तुलना करने की आवश्यकता है, तो हमें string.equals() विधि का उपयोग करने की आवश्यकता है।

स्ट्रिंग इंटर्निंग

अंत में, स्ट्रिंग इंटर्निंग पर विचार करें। आइए एक सरल उदाहरण पर एक नज़र डालें - एक कोड जो एक स्ट्रिंग को उलट देता है।

var s = "Strings are immutuble";
int length = s.Length;
for (int i = 0; i < length / 2; i++)
{
   var c = s[i];
   s[i] = s[length - i - 1];
   s[length - i - 1] = c;
}

जाहिर है, इस कोड को संकलित नहीं किया जा सकता है। कंपाइलर इन स्ट्रिंग्स के लिए त्रुटियों को फेंक देगा, क्योंकि हम स्ट्रिंग की सामग्री को संशोधित करने का प्रयास करते हैं। String वर्ग की कोई भी विधि इसके सामग्री संशोधन के बजाय, स्ट्रिंग का नया उदाहरण लौटाती है।

स्ट्रिंग को संशोधित किया जा सकता है, लेकिन हमें असुरक्षित कोड का उपयोग करने की आवश्यकता होगी। आइए निम्नलिखित उदाहरण पर विचार करें:

var s = "Strings are immutable";
int length = s.Length;
  unsafe
   {
    fixed (char* c = s)
     {
      for (int i = 0; i < length / 2; i++)
       {
         var temp = c[i];
         c[i] = c[length - i - 1];
         c[length - i - 1] = temp;
       }
      }
   }

इस कोड के निष्पादन के बाद, elbatummi युग sgnirtS अपेक्षित के रूप में स्ट्रिंग में लिखा जाएगा। स्ट्रिंग्स की परिवर्तनशीलता स्ट्रिंग इंटर्निंग से संबंधित एक फैंसी केस की ओर ले जाती है।

स्ट्रिंग इंटर्निंग एक ऐसा तंत्र है जहां समान अक्षर स्मृति में एक ही वस्तु के रूप में दर्शाए जाते हैं।

संक्षेप में, स्ट्रिंग इंटर्निंग का बिंदु निम्नलिखित है:एक प्रक्रिया के भीतर एक हैशेड आंतरिक तालिका होती है (किसी एप्लिकेशन डोमेन के भीतर नहीं), जिसमें स्ट्रिंग इसकी कुंजी होती है, और मान उनके संदर्भ होते हैं। JIT संकलन के दौरान, शाब्दिक स्ट्रिंग्स को क्रमिक रूप से एक तालिका में रखा जाता है (तालिका में प्रत्येक स्ट्रिंग केवल एक बार पाई जा सकती है)। निष्पादन के दौरान, इस तालिका से शाब्दिक तारों के संदर्भ दिए गए हैं। निष्पादन के दौरान, हम String.Intern . के साथ एक स्ट्रिंग को आंतरिक तालिका में रख सकते हैं तरीका। साथ ही, हम String.IsInterned . का उपयोग करके आंतरिक तालिका में एक स्ट्रिंग की उपलब्धता की जांच कर सकते हैं विधि।

var s1 = "habrahabr";
var s2 = "habrahabr";
var s3 = "habra" + "habr";

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

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

अब, अपने मामले पर वापस आते हैं। निम्नलिखित कोड पर विचार करें:

var s = "Strings are immutable";
int length = s.Length;
unsafe
 {
  fixed (char* c = s)
   {
    for (int i = 0; i < length / 2; i++)
     {
      var temp = c[i];
      c[i] = c[length - i - 1];
      c[length - i - 1] = temp;
     }
   }
 }
Console.WriteLine("Strings are immutable");

ऐसा लगता है कि सब कुछ काफी स्पष्ट है और कोड वापस आना चाहिए स्ट्रिंग अपरिवर्तनीय हैं . हालाँकि, ऐसा नहीं होता है! कोड लौटाता है elbatummi युग sgnirtS . यह बिल्कुल इंटर्निंग की वजह से होता है। जब हम स्ट्रिंग्स को संशोधित करते हैं, तो हम इसकी सामग्री को संशोधित करते हैं, और चूंकि यह शाब्दिक है, इसलिए इसे इंटर्न किया जाता है और स्ट्रिंग के एक उदाहरण द्वारा दर्शाया जाता है।

यदि हम CompilationRelaxationsAttribute लागू करते हैं तो हम स्ट्रिंग इंटर्निंग को छोड़ सकते हैं विधानसभा की विशेषता। यह विशेषता CLR वातावरण के JIT कंपाइलर द्वारा बनाए गए कोड की सटीकता को नियंत्रित करती है। इस विशेषता का निर्माता संकलन आराम . को स्वीकार करता है गणना, जिसमें वर्तमान में केवल CompilationRelaxations.NoStringInterning . शामिल है . नतीजतन, असेंबली को उस के रूप में चिह्नित किया जाता है जिसे इंटर्निंग की आवश्यकता नहीं होती है।

वैसे, यह विशेषता .NET Framework v1.0.में संसाधित नहीं होती है। इसलिए, इंटर्निंग को अक्षम करना असंभव था। संस्करण 2 से, mscorlib असेंबली इस विशेषता के साथ चिह्नित है। तो, यह पता चला है कि .NET में स्ट्रिंग्स को असुरक्षित कोड के साथ संशोधित किया जा सकता है।

अगर हम असुरक्षित के बारे में भूल जाएं तो क्या होगा?

जैसे ही होता है, हम असुरक्षित कोड के बिना स्ट्रिंग सामग्री को संशोधित कर सकते हैं। इसके बजाय, हम प्रतिबिंब तंत्र का उपयोग कर सकते हैं। यह ट्रिक .NET में वर्जन 2.0 तक सफल रही। बाद में, स्ट्रिंग वर्ग के डेवलपर्स ने हमें इस अवसर से वंचित कर दिया। .NET 2.0 में, स्ट्रिंग वर्ग की दो आंतरिक विधियाँ हैं:सेटचर सीमा जाँच और InternalSetCharNoBoundsCheck . के लिए जो सीमा की जाँच नहीं करता है। ये विधियां निर्दिष्ट वर्ण को एक निश्चित अनुक्रमणिका द्वारा सेट करती हैं। विधियों का कार्यान्वयन निम्न तरीके से दिखता है:

internal unsafe void SetChar(int index, char value)
 {
   if ((uint)index >= (uint)this.Length)
     throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
            
   fixed (char* chPtr = &this.m_firstChar)
          chPtr[index] = value;
 }

internal unsafe void InternalSetCharNoBoundsCheck (int index, char value)
 {
   fixed (char* chPtr = &this.m_firstChar)
          chPtr[index] = value;
 }

इसलिए, हम निम्नलिखित कोड की सहायता से असुरक्षित कोड के बिना स्ट्रिंग सामग्री को संशोधित कर सकते हैं:

var s = "Strings are immutable";
int length = s.Length;
var method = typeof(string).GetMethod("InternalSetCharNoBoundsCheck", BindingFlags.Instance | BindingFlags.NonPublic);
for (int i = 0; i < length / 2; i++)
  {
      var temp = s[i];
      method.Invoke(s, new object[] { i, s[length - i - 1] });
      method.Invoke(s, new object[] { length - i - 1, temp });
  }
            
 Console.WriteLine("Strings are immutable");

जैसा अपेक्षित था, कोड elbatummi युग sgnirtS returns लौटाता है ।

संस्करणों का मुद्दा :.NET Framework के विभिन्न संस्करणों में, string.Empty को एकीकृत किया जा सकता है या नहीं। आइए निम्नलिखित कोड पर विचार करें:

string str1 = String.Empty;
StringBuilder sb = new StringBuilder().Append(String.Empty);
string str2 = String.Intern(sb.ToString());	
		
if (object.ReferenceEquals(str1, str2))  
   Console.WriteLine("Equal");
else
   Console.WriteLine("Not Equal");

.NET Framework 1.0, .NET Framework 1.1 और .NET Framework 3.5 में 1 (SP1) सर्विस पैक के साथ, str1 और str2 समान नहीं हैं। वर्तमान में, string.खाली नजरबंद नहीं है।

प्रदर्शन के पहलू

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. एप्लिकेशन स्टैक का भविष्य

  2. शुरुआती के लिए SQL INSERT

  3. Clustered Columnstore Index से सीरियलाइज़िंग डिलीट्स

  4. घुटना-झटका प्रदर्शन ट्यूनिंग:अस्थायी तालिकाओं का गलत उपयोग

  5. sys.partitions का प्रदर्शन