CultureInfo

 
  1. // ==++==
  2. // 
  3. //   
  4. //    Copyright (c) 2002 Microsoft Corporation.  All rights reserved.
  5. //   
  6. //    The use and distribution terms for this software are contained in the file
  7. //    named license.txt, which can be found in the root of this distribution.
  8. //    By using this software in any fashion, you are agreeing to be bound by the
  9. //    terms of this license.
  10. //   
  11. //    You must not remove this notice, or any other, from this software.
  12. //   
  13. // 
  14. // ==--==
  15. ////////////////////////////////////////////////////////////////////////////
  16. //
  17. //  Class:    CultureInfo
  18. //
  19. //
  20. //  Purpose:  This class represents the software preferences of a particular
  21. //            culture or community.  It includes information such as the
  22. //            language, writing system, and a calendar used by the culture
  23. //            as well as methods for common operations such as printing
  24. //            dates and sorting strings.
  25. //
  26. //  Date:     March 31, 1999
  27. //
  28. ////////////////////////////////////////////////////////////////////////////
  29. namespace System.Globalization {    
  30.     using System;
  31.     using System.Threading;
  32.     using System.Runtime.CompilerServices;
  33.     
  34.     /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo"]/*' />
  35.     [Serializable] public class CultureInfo : ICloneable, IFormatProvider {
  36.         //
  37.         // Special culture IDs
  38.         //
  39.         internal const int InvariantCultureID = 0x007f;
  40.         internal const int zh_CHT_CultureID = 0x7c04;
  41.         
  42.         //--------------------------------------------------------------------//
  43.         //                        Internal Information                        //
  44.         //--------------------------------------------------------------------//
  45.     
  46.         // This is the string used to construct CultureInfo.
  47.         // It is in the format of ISO639 (2 letter language name) plus dash plus
  48.         // ISO 3166 (2 letter region name).  The language name is in lowercase and region name
  49.         // are in uppercase.
  50.         internal String m_name = null;
  51.     
  52.         //
  53.         // This points to a record in the Culture Data Table.  That record contains several fields
  54.         // There are two kinds of fields.  One is 16-bit integer data and another one is string data.
  55.         // These fields contains information about a particular culture.
  56.         // You can think of m_dataItem as a handle that can be used to call the following metdhos:
  57.         //      CultureTable.GetInt32Value()
  58.         //      CultureTable.GetStringValue()
  59.         //      CultureTable.GetMultipleStringValues()
  60.         //
  61.         // By calling these methods, you can get information about a culture.
  62.         internal int m_dataItem;
  63.         //
  64.         // This indicates that if we need to check for user-override values for this CultureInfo instance.
  65.         // For the user default culture of the system, user can choose to override some of the values
  66.         // associated with that culture.  For example, the default short-date format for en-US is
  67.         // "M/d/yyyy", however, one may change it to "dd/MM/yyyy" from the Regional Option in
  68.         // the control panel.
  69.         // So when a CultureInfo is created, one can specify if the create CultureInfo should check
  70.         // for user-override values, or should always get the default values.
  71.         //
  72.         internal bool m_useUserOverride;
  73.         //
  74.         // This is the culture ID used in the NLS+ world.  The concept of cultureID is similar
  75.         // to the concept of LCID in Win32.  However, NLS+ support "neutral" culture 
  76.         // which Win32 doesn't support.
  77.         //
  78.         // The format of culture ID (32 bits) is:
  79.         // 
  80.         // 31 - 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  81.         // +-----+ +---------+ +---------------+ +-----------------+
  82.         //    |         |           |            Primary language ID (10 bits)
  83.         //    |         |           +----------- Sublanguage ID (6 its)
  84.         //    |         +----------------------- Sort ID (4 bits)
  85.         //    +--------------------------------- Reserved (12 bits)
  86.         //
  87.         // Primary language ID and sublanguage ID can be zero to specify 'neutral' language.
  88.         // For example, cultureID 0x(0000)0009 is the English neutral culture.
  89.         // cultureID 0x(0000)0000 means the invariant culture (or called neutral culture).
  90.         //
  91.         internal int cultureID;
  92.         //Get the current user default culture.  This one is almost always used, so we create it by default.
  93.         internal static CultureInfo m_userDefaultCulture   = null;
  94.         
  95.         //
  96.         // All of the following will be created on demand.
  97.         //
  98.         
  99.         //The Invariant culture;
  100.         internal static CultureInfo m_InvariantCultureInfo = null
  101.         
  102.         //The culture used in the user interface. This is mostly used to load correct localized resources.
  103.         internal static CultureInfo m_userDefaultUICulture = null;
  104.         //This is the UI culture used to install the OS.
  105.         internal static CultureInfo m_InstalledUICultureInfo = null;
  106.         internal bool m_isReadOnly=false;        
  107.         internal CompareInfo compareInfo = null;
  108.         internal TextInfo textInfo = null;
  109.         internal NumberFormatInfo numInfo = null;
  110.         internal DateTimeFormatInfo dateTimeInfo = null;
  111.         internal Calendar calendar = null;
  112.             
  113.         //
  114.         //  Helper Methods.
  115.         //
  116.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  117.         internal static extern bool IsInstalledLCID(int LCID);
  118.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  119.         internal static extern int nativeGetUserDefaultLCID();
  120.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  121.         internal static extern int nativeGetUserDefaultUILanguage();
  122.         
  123.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  124.         internal static extern int nativeGetSystemDefaultUILanguage();
  125.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  126.         internal static extern int nativeGetThreadLocale();
  127.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  128.         internal static extern bool nativeSetThreadLocale(int LCID);
  129.         internal const int SPANISH_TRADITIONAL_SORT = 0x040a;
  130.         internal const int SPANISH_INTERNATIONAL_SORT = 0x0c0a;
  131.         static CultureInfo() {
  132.             CultureInfo temp = new CultureInfo(nativeGetUserDefaultLCID());
  133.             temp.m_isReadOnly = true;
  134.             m_userDefaultCulture = temp;
  135.         }
  136.         ////////////////////////////////////////////////////////////////////////
  137.         //
  138.         //  CultureInfo Constructors
  139.         //
  140.         ////////////////////////////////////////////////////////////////////////
  141.         
  142.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.CultureInfo"]/*' />
  143.         public CultureInfo(String name) : this(name, true) {
  144.         }
  145.         
  146.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.CultureInfo1"]/*' />
  147.         public CultureInfo(String name, bool useUserOverride) {
  148.             if (name==null) {
  149.                 throw new ArgumentNullException("name",
  150.                     Environment.GetResourceString("ArgumentNull_String"));
  151.                 
  152.             }
  153.     
  154.             this.m_dataItem = CultureTable.GetDataItemFromName(name);
  155.             if (m_dataItem < 0) {
  156.                 throw new ArgumentException(
  157.                     String.Format(Environment.GetResourceString("Argument_InvalidCultureName"), name), "name");
  158.             }
  159.             this.m_useUserOverride = useUserOverride;
  160.             
  161.             this.cultureID = CultureTable.GetDefaultInt32Value(m_dataItem, CultureTable.ILANGUAGE);
  162.         }
  163.     
  164.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.CultureInfo2"]/*' />
  165.         public CultureInfo(int culture) : this(culture, true) {
  166.         }
  167.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.CultureInfo3"]/*' />
  168.         public CultureInfo(int culture, bool useUserOverride) {
  169.             if (culture < 0) {
  170.                 throw new ArgumentOutOfRangeException("culture"
  171.                     Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
  172.             }
  173.             if (culture==SPANISH_TRADITIONAL_SORT) {
  174.                 // We are removing 0x040a (Spanish Traditional sort) in NLS+.  
  175.                 // So if you create 0x040a, it's just like 0x0c0a (Spanish International sort).
  176.                 // For a table setup reason, we can not really remove the data item for 0x040a in culture.nlp.
  177.                 // As a workaround, what we do is to make the data for 0x040a to be exactly the same as 0x0c0a.
  178.                 // Unfortunately, the culture name is the only exception.  
  179.                 // So in the table, we still have "es-ES-Ts" in there which we can not make it "es-ES".
  180.                 // Again, this is for table setup reason.  So if we are creating
  181.                 // CultureInfo using 0x040a, hardcode culture name to be "es-ES" here so that we won't
  182.                 // get "es-ES-Ts" in the table.
  183.                 m_name = "es-ES";
  184.             }
  185.             m_dataItem = CultureTable.GetDataItemFromCultureID(GetLangID(culture));            
  186.             if (m_dataItem < 0) {
  187.                 throw new ArgumentException(
  188.                     String.Format(Environment.GetResourceString("Argument_CultureNotSupported"), culture), "culture");
  189.             }
  190.             this.m_useUserOverride = useUserOverride;            
  191.             int sortID;
  192.             if ((sortID = GetSortID(culture))!= 0) {
  193.                 //
  194.                 // Check if the sort ID is valid.
  195.                 //
  196.                 if (!CultureTable.IsValidSortID(m_dataItem, sortID)) {
  197.                     throw new ArgumentException(
  198.                         String.Format(Environment.GetResourceString("Argument_CultureNotSupported"), culture), "culture");            
  199.                 }
  200.             }
  201.             this.cultureID = culture;
  202.         }
  203.         private const int NEUTRAL_SPANISH_CULTURE = 0x0A; //This is the lcid for neutral spanish.
  204.         private const int INTERNATIONAL_SPANISH_CULTURE = 0x0C0A;  //This is the LCID for international spanish.
  205.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.CreateSpecificCulture"]/*' />
  206.         public static CultureInfo CreateSpecificCulture(String name) {
  207.             CultureInfo culture = new CultureInfo(name);
  208.             //In the most common case, they've given us a specific culture, so we'll just return that.
  209.             if (!(culture.IsNeutralCulture)) {
  210.                 return culture;
  211.             }
  212.             
  213.             int lcid = culture.LCID;
  214.             //If we have the Chinese locale, we have no way of producing a 
  215.             //specific culture without encountering significant geopolitical
  216.             //issues.  Based on that, we have no choice but to bail.
  217.             if ((lcid & 0x3FF)==0x04) {
  218.                 throw new ArgumentException(Environment.GetResourceString("Argument_NoSpecificCulture"));
  219.             }
  220.             //I've made this a switch statement because I believe that the number fo exceptions which we're going
  221.             //to have is going to grow.
  222.             switch(lcid) {
  223.             case NEUTRAL_SPANISH_CULTURE:
  224.                 return new CultureInfo(INTERNATIONAL_SPANISH_CULTURE);
  225.             }
  226.             //This is the algorithm that windows uses for determing the "first"
  227.             //culture associated with a neutral language.  The low-order 18 bits
  228.             //of an LCID are consumed with the language ID, so this is essentially
  229.             //a 1 in the culture id field.
  230.             lcid |= 0x0400;
  231.                 
  232.             return new CultureInfo(lcid);
  233.         }
  234.         internal static bool VerifyCultureName(CultureInfo culture, bool throwException) {
  235.             BCLDebug.Assert(culture!=null"[CultureInfo.VerifyCultureName]culture!=null");
  236.             //If we have an instance of one of our CultureInfos, the user can't have changed the
  237.             //name and we know that all names are valid in files.
  238.             if (culture.GetType()==typeof(CultureInfo)) {
  239.                 return true;
  240.             }
  241.             
  242.             String name = culture.Name;
  243.             
  244.             for (int i=0; i<name.Length; i++) {
  245.                 char c = name[i];
  246.                 if (Char.IsLetterOrDigit(c) || c=='-' || c=='_') {
  247.                     continue;
  248.                 }
  249.                 if (throwException) {
  250.                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidResourceCultureName", name));
  251.                 }
  252.                 return false;
  253.             }
  254.             return true;
  255.         }
  256.         //--------------------------------------------------------------------//
  257.         //                        Misc static functions                       //
  258.         //--------------------------------------------------------------------//
  259.     
  260.         internal static int GetPrimaryLangID(int culture)
  261.         {
  262.             return (culture & 0x03ff);            
  263.         }
  264.     
  265.         internal static int GetSubLangID(int culture)
  266.         {
  267.             return ((culture >> 10) & 0x3f);
  268.         }
  269.     
  270.         internal static int GetLangID(int culture)
  271.         {
  272.             return (culture & 0xffff);
  273.         }
  274.     
  275.         internal static int MakeLangID(int primaryLangID, int subLangID)
  276.         {
  277.             BCLDebug.Assert(primaryLangID >= 0 && primaryLangID < 1024, "CultureInfo.makeLangID(): primaryLangID >= 0 && primaryLangID < 1024");
  278.             BCLDebug.Assert(subLangID >= 0 && subLangID < 64, "CultureInfo.makeLangID(): subLangID >= 0 && subLangID < 64");
  279.             return ((subLangID << 10)| primaryLangID);
  280.         }
  281.     
  282.         internal static int GetSortID(int lcid)   
  283.         {
  284.             return ((lcid >> 16) & 0xf);
  285.         }
  286.             
  287.         ////////////////////////////////////////////////////////////////////////
  288.         //
  289.         //  CurrentCulture
  290.         //
  291.         //  This instance provides methods based on the current user settings.
  292.         //  These settings are volatile and may change over the lifetime of the
  293.         //  thread.
  294.         //
  295.         ////////////////////////////////////////////////////////////////////////
  296.     
  297.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.CurrentCulture"]/*' />
  298.         public static CultureInfo CurrentCulture
  299.         {
  300.             get {
  301.                 return Thread.CurrentThread.CurrentCulture;
  302.             }
  303.         }
  304.         //
  305.         // This is the equivalence of the Win32 GetUserDefaultLCID()
  306.         //
  307.         internal static CultureInfo UserDefaultCulture {
  308.             get {
  309.                 return (m_userDefaultCulture);
  310.             }
  311.         }
  312.     
  313.         //
  314.         //  This is the equivalence of the Win32 GetUserDefaultUILanguage()
  315.         //
  316.     
  317.         internal static CultureInfo UserDefaultUICulture {
  318.             get {
  319.                 if (m_userDefaultUICulture == null) {
  320.                     CultureInfo temp = new CultureInfo(nativeGetUserDefaultUILanguage()); ;
  321.                     temp.m_isReadOnly = true;
  322.                     m_userDefaultUICulture = temp;
  323.                 }
  324.                 return (m_userDefaultUICulture);    
  325.             }
  326.         }
  327.     
  328.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.CurrentUICulture"]/*' />
  329.         public static CultureInfo CurrentUICulture {
  330.             get {
  331.                 return Thread.CurrentThread.CurrentUICulture;
  332.             }
  333.         }
  334.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.InstalledUICulture"]/*' />
  335.         //
  336.         // This is the equivalence of the Win32 GetSystemDefaultUILanguage()
  337.         //
  338.         public static CultureInfo InstalledUICulture {
  339.             get {
  340.                 if (m_InstalledUICultureInfo == null) {
  341.                     CultureInfo temp = new CultureInfo(nativeGetSystemDefaultUILanguage());
  342.                     temp.m_isReadOnly = true;
  343.                     m_InstalledUICultureInfo = temp;
  344.                 }
  345.                 return (m_InstalledUICultureInfo);
  346.             }
  347.         }
  348.     
  349.         ////////////////////////////////////////////////////////////////////////
  350.         //
  351.         //  InvariantCulture
  352.         //
  353.         //  This instance provides methods, for example for casing and sorting,
  354.         //  that are independent of the system and current user settings.  It
  355.         //  should be used only by processes such as some system services that
  356.         //  require such invariant results (eg. file systems).  In general,
  357.         //  the results are not linguistically correct and do not match any
  358.         //  culture info.
  359.         //
  360.         ////////////////////////////////////////////////////////////////////////
  361.     
  362.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.InvariantCulture"]/*' />
  363.         public static CultureInfo InvariantCulture {
  364.             get {
  365.                 if (m_InvariantCultureInfo == null) {
  366.                     CultureInfo temp = new CultureInfo(InvariantCultureID, false);
  367.                     temp.m_isReadOnly = true;
  368.                     m_InvariantCultureInfo = temp;
  369.                 }
  370.                 return (m_InvariantCultureInfo);
  371.             }
  372.         }
  373.     
  374.     
  375.         ////////////////////////////////////////////////////////////////////////
  376.         //
  377.         //  Parent
  378.         //
  379.         //  Return the parent CultureInfo for the current instance.
  380.         //
  381.         ////////////////////////////////////////////////////////////////////////
  382.     
  383.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.Parent"]/*' />
  384.         public virtual CultureInfo Parent {
  385.             get {
  386.                 int parentCulture = CultureTable.GetDefaultInt32Value(m_dataItem, CultureTable.IPARENT);
  387.                 if (parentCulture == InvariantCultureID) {
  388.                     return (InvariantCulture);
  389.                 }
  390.                 return (new CultureInfo(parentCulture, m_useUserOverride));
  391.             }
  392.         }
  393.     
  394.         ////////////////////////////////////////////////////////////////////////
  395.         //
  396.         //  LCID
  397.         //
  398.         //  Returns a properly formed culture identifier for the current
  399.         //  culture info.
  400.         //
  401.         ////////////////////////////////////////////////////////////////////////
  402.     
  403.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.LCID"]/*' />
  404.         public virtual int LCID {
  405.             get {
  406.                 return (this.cultureID);
  407.             }
  408.         }
  409.             
  410.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.GetCultures"]/*' />
  411.         public static CultureInfo[] GetCultures(CultureTypes types) {
  412.             return (CultureTable.GetCultures(types));
  413.         }
  414.     
  415.         ////////////////////////////////////////////////////////////////////////
  416.         //
  417.         //  Name
  418.         //
  419.         //  Returns the full name of the CultureInfo. The name is in format like
  420.         //  "en-US"
  421.         //
  422.         ////////////////////////////////////////////////////////////////////////
  423.     
  424.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.Name"]/*' />
  425.         public virtual String Name {
  426.             get {
  427.                 if (m_name==null) {
  428.                     m_name = CultureTable.GetDefaultStringValue(m_dataItem, CultureTable.SNAME);
  429.                 }
  430.                 return m_name;    
  431.             }
  432.         }
  433.         ////////////////////////////////////////////////////////////////////////
  434.         //
  435.         //  DisplayName
  436.         //
  437.         //  Returns the full name of the CultureInfo in the localized language.
  438.         //  For example, if the localized language of the runtime is Spanish and the CultureInfo is
  439.         //  US English, "Ingles (Estados Unidos)" will be returned.
  440.         //
  441.         ////////////////////////////////////////////////////////////////////////
  442.         
  443.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.DisplayName"]/*' />
  444.         public virtual String DisplayName {
  445.             get {
  446.                 return (Environment.GetResourceString("Globalization.ci_"+Name));
  447.             }
  448.         }
  449.         
  450.         ////////////////////////////////////////////////////////////////////////
  451.         //
  452.         //  GetNativeName
  453.         //
  454.         //  Returns the full name of the CultureInfo in the native language.
  455.         //  For example, if the CultureInfo is US English, "English
  456.         //  (United States)" will be returned.
  457.         //
  458.         ////////////////////////////////////////////////////////////////////////
  459.     
  460.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.NativeName"]/*' />
  461.         public virtual String NativeName {
  462.             get {
  463.                 return (CultureTable.GetDefaultStringValue(m_dataItem, CultureTable.SNATIVEDISPLAYNAME));
  464.             }
  465.         }
  466.         
  467.         ////////////////////////////////////////////////////////////////////////
  468.         //
  469.         //  GetEnglishName
  470.         //
  471.         //  Returns the full name of the CultureInfo in English.
  472.         //  For example, if the CultureInfo is US English, "English
  473.         //  (United States)" will be returned.
  474.         //
  475.         ////////////////////////////////////////////////////////////////////////
  476.     
  477.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.EnglishName"]/*' />
  478.         public virtual String EnglishName {
  479.             get {
  480.                 return (CultureTable.GetDefaultStringValue(m_dataItem, CultureTable.SENGDISPLAYNAME));
  481.             }
  482.         }
  483.     
  484.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.TwoLetterISOLanguageName"]/*' />
  485.         public virtual String TwoLetterISOLanguageName {
  486.             get {
  487.                 return (CultureTable.GetDefaultStringValue(m_dataItem, CultureTable.SISO639LANGNAME));        
  488.             }
  489.         }
  490.         
  491.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.ThreeLetterISOLanguageName"]/*' />
  492.         public virtual String ThreeLetterISOLanguageName {
  493.             get {
  494.                 return (CultureTable.GetDefaultStringValue(m_dataItem, CultureTable.SISO639LANGNAME2));        
  495.             }
  496.         }
  497.     
  498.         ////////////////////////////////////////////////////////////////////////
  499.         //
  500.         //  GetAbbreviatedName
  501.         //
  502.         //  Returns the abbreviated name for the current instance.  The
  503.         //  abbreviated form is usually based on the ISO 639 standard, for
  504.         //  example the two letter abbreviation for English is "en".
  505.         //
  506.         ////////////////////////////////////////////////////////////////////////
  507.     
  508.        /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.ThreeLetterWindowsLanguageName"]/*' />
  509.        public virtual String ThreeLetterWindowsLanguageName {
  510.             get {
  511.                 return (CultureTable.GetDefaultStringValue(m_dataItem, CultureTable.SABBREVLANGNAME));
  512.             }
  513.         }
  514.         ////////////////////////////////////////////////////////////////////////
  515.         //
  516.         //  CompareInfo               Read-Only Property
  517.         //
  518.         //  Gets the CompareInfo for this culture.
  519.         //
  520.         ////////////////////////////////////////////////////////////////////////
  521.     
  522.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.CompareInfo"]/*' />
  523.         public virtual CompareInfo CompareInfo {
  524.             get {
  525.                 if (compareInfo==null) {
  526.                     compareInfo = CompareInfo.GetCompareInfo(cultureID);
  527.                 }                            
  528.                 return (compareInfo);
  529.             }
  530.         }
  531.     
  532.         ////////////////////////////////////////////////////////////////////////
  533.         //
  534.         //  TextInfo
  535.         //
  536.         //  Gets the TextInfo for this culture.
  537.         //
  538.         ////////////////////////////////////////////////////////////////////////
  539.     
  540.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.TextInfo"]/*' />
  541.         public virtual TextInfo TextInfo {
  542.             get {            
  543.                 if (textInfo==null) {
  544.                     textInfo = new TextInfo(cultureID, m_dataItem, m_useUserOverride);
  545.                 }
  546.                 return (textInfo);
  547.             }
  548.         } 
  549.     
  550.         ////////////////////////////////////////////////////////////////////////
  551.         //
  552.         //  Equals
  553.         //
  554.         //  Implements Object.Equals().  Returns a boolean indicating whether
  555.         //  or not object refers to the same CultureInfo as the current instance.
  556.         //
  557.         ////////////////////////////////////////////////////////////////////////
  558.     
  559.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.Equals"]/*' />
  560.         public override bool Equals(Object value) {
  561.             //
  562.             //  See if the object name is the same as the culture info object.
  563.             //
  564.             if ((value != null) && (value is CultureInfo)) {
  565.                 CultureInfo culture = (CultureInfo)value;
  566.     
  567.                 //
  568.                 //  See if the member variables are equal.  If so, then
  569.                 //  return true.
  570.                 //
  571.                 if (this.cultureID == culture.cultureID) {
  572.                     return (true);
  573.                 }
  574.             }
  575.     
  576.             //
  577.             //  Objects are not the same, so return false.
  578.             //
  579.             return (false);
  580.         }
  581.     
  582.     
  583.         ////////////////////////////////////////////////////////////////////////
  584.         //
  585.         //  GetHashCode
  586.         //
  587.         //  Implements Object.GetHashCode().  Returns the hash code for the
  588.         //  CultureInfo.  The hash code is guaranteed to be the same for CultureInfo A
  589.         //  and B where A.Equals(B) is true.
  590.         //
  591.         ////////////////////////////////////////////////////////////////////////
  592.     
  593.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.GetHashCode"]/*' />
  594.         public override int GetHashCode() {
  595.             return (this.LCID);
  596.         }
  597.     
  598.     
  599.         ////////////////////////////////////////////////////////////////////////
  600.         //
  601.         //  ToString
  602.         //
  603.         //  Implements Object.ToString().  Returns the name of the CultureInfo,
  604.         //  eg. "English (United States)".
  605.         //
  606.         ////////////////////////////////////////////////////////////////////////
  607.     
  608.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.ToString"]/*' />
  609.         public override String ToString() {
  610.             return (Name);
  611.         }
  612.     
  613.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.GetFormat"]/*' />
  614.         public virtual Object GetFormat(Type formatType) {
  615.             if (formatType == typeof(NumberFormatInfo)) {
  616.                 return (NumberFormat);
  617.             }
  618.             if (formatType == typeof(DateTimeFormatInfo)) {
  619.                 return (DateTimeFormat);
  620.             }
  621.             return (null);
  622.         }        
  623.         
  624.         private static readonly char[] groupSeparator = new char[] {';'};
  625.         /*=================================ParseGroupString==========================
  626.         **Action: The number grouping information is stored as string.  The group numbers
  627.         **        are separated by comma.  The function split the numbers and return
  628.         **        the result as an int array.
  629.         **Returns: An array of int for the number grouping information.
  630.         **Arguments: a number grouping string.
  631.         **Exceptions: None.
  632.         ============================================================================*/
  633.         
  634.         internal static int[] ParseGroupString(String groupStr) {
  635.             BCLDebug.Assert(groupStr != null"groupStr should not be null. There is data error in culture.nlp.");
  636.             String[] groupDigits = groupStr.Split(groupSeparator);
  637.             BCLDebug.Assert(groupDigits.Length > 0, "There is data error in culture.nlp.");
  638.             int[] result = new int[groupDigits.Length];
  639.             try {
  640.                 for (int i=0; i < groupDigits.Length; i++) {
  641.                     result[i] = Int32.Parse(groupDigits[i], NumberStyles.None, NumberFormatInfo.InvariantInfo);
  642.                 }
  643.             } catch (Exception) {
  644.                 BCLDebug.Assert(true"There is data error in culture.nlp.");
  645.             }
  646.             return (result);
  647.         }
  648.     
  649.         internal static void CheckNeutral(CultureInfo culture) {
  650.             if (culture.IsNeutralCulture) {
  651.                     throw new NotSupportedException(
  652.                                                     Environment.GetResourceString("Argument_CultureInvalidFormat"
  653.                                                     culture.Name));
  654.             }
  655.         }
  656.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.IsNeutralCulture"]/*' />
  657.         public virtual bool IsNeutralCulture {
  658.             get {
  659.                 return (cultureID!=InvariantCultureID && CultureTable.IsNeutralCulture(cultureID));
  660.             }
  661.         }
  662.         
  663.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.NumberFormat"]/*' />
  664.         public virtual NumberFormatInfo NumberFormat {
  665.             get {
  666.                 CultureInfo.CheckNeutral(this);
  667.                 if (numInfo == null) {
  668.                     NumberFormatInfo temp = new NumberFormatInfo(m_dataItem, m_useUserOverride);
  669.                     temp.isReadOnly = m_isReadOnly;
  670.                     numInfo = temp;
  671.                 }
  672.                 return (numInfo);
  673.             }
  674.             set {
  675.                 VerifyWritable();
  676.                 if (value == null) {
  677.                     throw new ArgumentNullException("value",
  678.                         Environment.GetResourceString("ArgumentNull_Obj"));                    
  679.                 }
  680.                 numInfo = value;
  681.             }
  682.         }
  683.         ////////////////////////////////////////////////////////////////////////
  684.         //
  685.         // GetDateTimeFormatInfo
  686.         // 
  687.         // Create a DateTimeFormatInfo, and fill in the properties according to
  688.         // the CultureID.
  689.         //
  690.         ////////////////////////////////////////////////////////////////////////
  691.         
  692.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.DateTimeFormat"]/*' />
  693.         public virtual DateTimeFormatInfo DateTimeFormat {
  694.             get {
  695.                 CultureInfo.CheckNeutral(this);
  696.                 if (dateTimeInfo == null) { 
  697.                     lock(this) {
  698.                         if (dateTimeInfo == null) {
  699.                             // Change the calendar of DTFI to the specified calendar of this CultureInfo.
  700.                             DateTimeFormatInfo temp = new DateTimeFormatInfo(GetLangID(cultureID), m_dataItem, m_useUserOverride, this.Calendar);
  701.                             temp.m_isReadOnly = m_isReadOnly;
  702.                             dateTimeInfo = temp;
  703.                         }
  704.                     }
  705.                 }
  706.                 return (dateTimeInfo);
  707.             }
  708.             set {
  709.                 VerifyWritable();
  710.                 if (value == null) {
  711.                     throw new ArgumentNullException("value",
  712.                         Environment.GetResourceString("ArgumentNull_Obj"));                    
  713.                 }                
  714.                 dateTimeInfo = value;
  715.             }                            
  716.         }
  717.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.ClearCachedData"]/*' />
  718.         public void ClearCachedData() {
  719.             lock(typeof(CultureInfo)) {
  720.                 m_userDefaultUICulture = null;
  721.                 CultureInfo temp = new CultureInfo(nativeGetUserDefaultLCID());
  722.                 temp.m_isReadOnly = true;
  723.                 m_userDefaultCulture = temp;
  724.                 RegionInfo.m_currentRegionInfo = null;                
  725.                 
  726.                 TimeZone.ResetTimeZone();
  727.             }
  728.         }
  729.         /*=================================GetCalendarInstance==========================
  730.         **Action: Map a Win32 CALID to an instance of supported calendar.
  731.         **Returns: An instance of calendar.
  732.         **Arguments: calType    The Win32 CALID
  733.         **Exceptions:
  734.         **      Shouldn't throw exception since the calType value is from our data table or from Win32 registry.
  735.         **      If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar.
  736.         ============================================================================*/
  737.         internal Calendar GetCalendarInstance(int calType) {
  738.             if (calType==Calendar.CAL_GREGORIAN) {
  739.                 return (GregorianCalendar.GetDefaultInstance());
  740.             }
  741.             return GetCalendarInstanceRare(calType);
  742.         }
  743.         
  744.         //This function exists as a hack to prevent us from loading all of the non-gregorian
  745.         //calendars unless they're required.  
  746.         internal Calendar GetCalendarInstanceRare(int calType) {
  747.             BCLDebug.Assert(calType!=Calendar.CAL_GREGORIAN, "calType!=Calendar.CAL_GREGORIAN");
  748.             switch (calType) {
  749.                 case Calendar.CAL_GREGORIAN_US:               // Gregorian (U.S.) calendar
  750.                 case Calendar.CAL_GREGORIAN_ME_FRENCH:        // Gregorian Middle East French calendar
  751.                 case Calendar.CAL_GREGORIAN_ARABIC:           // Gregorian Arabic calendar
  752.                 case Calendar.CAL_GREGORIAN_XLIT_ENGLISH:     // Gregorian Transliterated English calendar
  753.                 case Calendar.CAL_GREGORIAN_XLIT_FRENCH:      // Gregorian Transliterated French calendar
  754.                     return (new GregorianCalendar((GregorianCalendarTypes)calType));
  755.                 case Calendar.CAL_TAIWAN:                     // Taiwan Era calendar
  756.                     return (TaiwanCalendar.GetDefaultInstance());
  757.                 case Calendar.CAL_JAPAN:                      // Japanese Emperor Era calendar
  758.                     return (JapaneseCalendar.GetDefaultInstance());
  759.                 case Calendar.CAL_KOREA:                      // Korean Tangun Era calendar
  760.                     return (KoreanCalendar.GetDefaultInstance());
  761.                 case Calendar.CAL_HIJRI:                      // Hijri (Arabic Lunar) calendar
  762.                     return (HijriCalendar.GetDefaultInstance());
  763.                 case Calendar.CAL_THAI:                       // Thai calendar
  764.                     return (ThaiBuddhistCalendar.GetDefaultInstance());
  765.                 case Calendar.CAL_HEBREW:                     // Hebrew (Lunar) calendar            
  766.                     return (HebrewCalendar.GetDefaultInstance());
  767.             }
  768.             return (GregorianCalendar.GetDefaultInstance());
  769.         }
  770.         
  771.         /*=================================Calendar==========================
  772.         **Action: Return/set the calendar used by this culture.
  773.         **Returns:
  774.         **Arguments:
  775.         **Exceptions:
  776.         **  ArgumentNull_Obj if the set value is null.
  777.         ============================================================================*/
  778.         
  779.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.Calendar"]/*' />
  780.         public virtual Calendar Calendar {
  781.             get {
  782.                 if (calendar == null) {
  783.                     lock(this) {
  784.                         if (calendar == null) {
  785.                             // Get the default calendar for this culture.  Note that the value can be
  786.                             // from registry if this is a user default culture.
  787.                             int calType = CultureTable.GetInt32Value(m_dataItem, CultureTable.ICALENDARTYPE, m_useUserOverride);
  788.                             calendar = GetCalendarInstance(calType);
  789.                         }
  790.                     }
  791.                 }
  792.                 return (calendar);
  793.             }
  794.         }
  795.         /*=================================OptionCalendars==========================
  796.         **Action: Return an array of the optional calendar for this culture.
  797.         **Returns: an array of Calendar.
  798.         **Arguments:
  799.         **Exceptions:
  800.         ============================================================================*/
  801.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.OptionalCalendars"]/*' />
  802.         public virtual Calendar[] OptionalCalendars {
  803.             get {
  804.                 //
  805.                 // This property always returns a new copy of the calendar array.
  806.                 //
  807.                 int[] calID = ParseGroupString(CultureTable.GetDefaultStringValue(m_dataItem, CultureTable.NLPIOPTIONCALENDAR));
  808.                 Calendar [] cals = new Calendar[calID.Length];
  809.                 for (int i = 0; i < cals.Length; i++) {
  810.                     cals[i] = GetCalendarInstance(calID[i]);
  811.                 }
  812.                 return (cals);
  813.             }
  814.         }        
  815.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.UseUserOverride"]/*' />
  816.         public bool UseUserOverride { 
  817.             get {
  818.                 return (m_useUserOverride);
  819.             }
  820.         }        
  821.     
  822.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.Clone"]/*' />
  823.         public virtual Object Clone()
  824.         {
  825.             CultureInfo ci = (CultureInfo)MemberwiseClone();
  826.             //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
  827.             //they've already been allocated.  If this is a derived type, we'll take a more generic codepath.
  828.             if (ci.GetType()==typeof(CultureInfo)) {
  829.                 if (dateTimeInfo != null) {
  830.                     ci.dateTimeInfo = (DateTimeFormatInfo)dateTimeInfo.Clone();
  831.                 }
  832.                 if (numInfo != null) {
  833.                     ci.numInfo = (NumberFormatInfo)numInfo.Clone();
  834.                 }
  835.                 ci.m_isReadOnly = false;
  836.             } else {
  837.                 ci.m_isReadOnly = false;
  838.                 ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone();
  839.                 ci.NumberFormat   = (NumberFormatInfo)this.NumberFormat.Clone();
  840.             }
  841.             return (ci);
  842.         }        
  843.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.ReadOnly"]/*' />        
  844.         public static CultureInfo ReadOnly(CultureInfo ci) {
  845.             if (ci == null) {
  846.                 throw new ArgumentNullException("ci");
  847.             }
  848.             if (ci.IsReadOnly) {
  849.                 return (ci);
  850.             }
  851.             CultureInfo info = (CultureInfo)(ci.MemberwiseClone());
  852.             //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
  853.             //they've already been allocated.  If this is a derived type, we'll take a more generic codepath.
  854.             if (ci.GetType()==typeof(CultureInfo)) {
  855.                 if (ci.dateTimeInfo != null) {
  856.                     info.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo);
  857.                 }
  858.                 if (ci.numInfo != null) {
  859.                     info.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo);
  860.                 }
  861.             } else {
  862.                 info.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
  863.                 info.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
  864.             }
  865.             // Don't set the read-only flag too early.
  866.             // We should set the read-only flag here.  Otherwise, info.DateTimeFormat will not be able to set.
  867.             info.m_isReadOnly = true;
  868.             
  869.             return (info);
  870.         }
  871.         /// <include file='doc/CultureInfo.uex' path='docs/doc[@for="CultureInfo.IsReadOnly"]/*' />
  872.         public bool IsReadOnly {
  873.             get {
  874.                 return (m_isReadOnly);
  875.             }
  876.         }
  877.         private void VerifyWritable() {
  878.             if (m_isReadOnly) {
  879.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
  880.             }
  881.         }        
  882.     }    
  883. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值