// Helper function both both overloads of GetCachedReadOnlyCulture. If lcid is 0, we use the name. // If lcid is -1, use the altName and create one of those special SQL cultures. internal static CultureInfo GetCultureInfoHelper(int lcid, string name, string altName) { // retval is our return value. CultureInfo retval; // Temporary hashtable for the names. StringCultureInfoDictionary tempNameHT = s_NameCachedCultures; if (name != null) { name = CultureData.AnsiToLower(name); } if (altName != null) { altName = CultureData.AnsiToLower(altName); } // We expect the same result for both hashtables, but will test individually for added safety. if (tempNameHT == null) { tempNameHT = new StringCultureInfoDictionary(); } else { // If we are called by name, check if the object exists in the hashtable. If so, return it. if (lcid == -1 || lcid == 0) { bool ret; lock (m_lock) { ret = tempNameHT.TryGetValue(lcid == 0 ? name : name + '\xfffd' + altName, out retval); } if (ret && retval != null) { return(retval); } } } // Next, the Lcid table. StringLcidDictionary tempLcidHT = s_LcidCachedCultures; if (tempLcidHT == null) { // Case insensitive is not an issue here, save the constructor call. tempLcidHT = new StringLcidDictionary(); } else { // If we were called by Lcid, check if the object exists in the table. If so, return it. if (lcid > 0) { bool ret; lock (m_lock) { ret = tempLcidHT.TryGetValue(lcid, out retval); } if (ret && retval != null) { return(retval); } } } // We now have two temporary hashtables and the desired object was not found. // We'll construct it. We catch any exceptions from the constructor call and return null. try { switch (lcid) { case -1: // call the private constructor retval = new CultureInfo(name, altName); break; case 0: retval = new CultureInfo(name, false); break; default: retval = new CultureInfo(lcid, false); break; } } catch (ArgumentException) { return(null); } // Set it to read-only retval.m_isReadOnly = true; if (lcid == -1) { lock (m_lock) { // This new culture will be added only to the name hash table. tempNameHT[name + '\xfffd' + altName] = retval; } // when lcid == -1 then TextInfo object is already get created and we need to set it as read only. retval.TextInfo.SetReadOnlyState(true); } else if (lcid == 0) { // Remember our name (as constructed). Do NOT use alternate sort name versions because // we have internal state representing the sort. (So someone would get the wrong cached version) string newName = CultureData.AnsiToLower(retval.m_name); // We add this new culture info object to both tables. lock (m_lock) { tempNameHT[newName] = retval; } } else { lock (m_lock) { tempLcidHT[lcid] = retval; } } // Copy the two hashtables to the corresponding member variables. This will potentially overwrite // new tables simultaneously created by a new thread, but maximizes thread safety. if (-1 != lcid) { // Only when we modify the lcid hash table, is there a need to overwrite. s_LcidCachedCultures = tempLcidHT; } s_NameCachedCultures = tempNameHT; // Finally, return our new CultureInfo object. return(retval); }
// Helper function both both overloads of GetCachedReadOnlyCulture. internal static CultureInfo GetCultureInfoHelper(string name) { // There is a race condition in this code with the side effect that the second thread's value // clobbers the first in the dictionary. This is an acceptable race since the CultureInfo objects // are content equal (but not reference equal). Since we make no guarantees there, this race is // acceptable. // retval is our return value. CultureInfo retval; if (name == null) { return(null); } // Temporary hashtable for the names. LowLevelDictionary <string, CultureInfo> tempNameHT = s_NameCachedCultures; name = CultureData.AnsiToLower(name); // We expect the same result for both hashtables, but will test individually for added safety. if (tempNameHT == null) { tempNameHT = new LowLevelDictionary <string, CultureInfo>(); } else { bool ret; lock (s_lock) { ret = tempNameHT.TryGetValue(name, out retval); } if (ret && retval != null) { return(retval); } } try { retval = new CultureInfo(name, false); } catch (ArgumentException) { return(null); } // Set it to read-only retval._isReadOnly = true; // Remember our name (as constructed). Do NOT use alternate sort name versions because // we have internal state representing the sort. (So someone would get the wrong cached version) string newName = CultureData.AnsiToLower(retval.m_name); // We add this new culture info object to both tables. lock (s_lock) { tempNameHT[newName] = retval; } s_NameCachedCultures = tempNameHT; // Finally, return our new CultureInfo object. return(retval); }
internal static CultureInfo GetCultureInfoHelper(int lcid, string name, string altName) { CultureInfo info; Hashtable hashtable = s_NameCachedCultures; if (name != null) { name = CultureData.AnsiToLower(name); } if (altName != null) { altName = CultureData.AnsiToLower(altName); } if (hashtable == null) { hashtable = Hashtable.Synchronized(new Hashtable()); } else if (lcid == -1) { info = (CultureInfo)hashtable[name + ((char)0xfffd) + altName]; if (info != null) { return(info); } } else if (lcid == 0) { info = (CultureInfo)hashtable[name]; if (info != null) { return(info); } } Hashtable hashtable2 = s_LcidCachedCultures; if (hashtable2 == null) { hashtable2 = Hashtable.Synchronized(new Hashtable()); } else if (lcid > 0) { info = (CultureInfo)hashtable2[lcid]; if (info != null) { return(info); } } try { switch (lcid) { case -1: info = new CultureInfo(name, altName); goto Label_00D5; case 0: info = new CultureInfo(name, false); goto Label_00D5; } info = new CultureInfo(lcid, false); } catch (ArgumentException) { return(null); } Label_00D5: info.m_isReadOnly = true; if (lcid == -1) { hashtable[name + ((char)0xfffd) + altName] = info; info.TextInfo.SetReadOnlyState(true); } else { string str = CultureData.AnsiToLower(info.m_name); hashtable[str] = info; if (((info.LCID != 4) || (str != "zh-hans")) && ((info.LCID != 0x7c04) || (str != "zh-hant"))) { hashtable2[info.LCID] = info; } } if (-1 != lcid) { s_LcidCachedCultures = hashtable2; } s_NameCachedCultures = hashtable; return(info); }