From: Hugh Bellamy Date: Thu, 7 Mar 2019 14:39:23 +0000 (+0000) Subject: Cleanup Globalization info code (#22591) X-Git-Tag: accepted/tizen/unified/20190813.215958~61^2~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=724112354c74b67629d58d1f6b9c0007f5a13fc9;p=platform%2Fupstream%2Fcoreclr.git Cleanup Globalization info code (#22591) --- diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs index 644230c..80b52e6 100644 --- a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs @@ -10,12 +10,28 @@ internal static partial class Interop internal static unsafe partial class Kernel32 { internal const uint LOCALE_ALLOW_NEUTRAL_NAMES = 0x08000000; // Flag to allow returning neutral names/lcids for name conversion + internal const uint LOCALE_ILANGUAGE = 0x00000001; internal const uint LOCALE_SUPPLEMENTAL = 0x00000002; internal const uint LOCALE_REPLACEMENT = 0x00000008; internal const uint LOCALE_NEUTRALDATA = 0x00000010; internal const uint LOCALE_SPECIFICDATA = 0x00000020; + internal const uint LOCALE_SISO3166CTRYNAME = 0x0000005A; + internal const uint LOCALE_SNAME = 0x0000005C; + internal const uint LOCALE_INEUTRAL = 0x00000071; + internal const uint LOCALE_SSHORTTIME = 0x00000079; + internal const uint LOCALE_STIMEFORMAT = 0x00001003; + internal const uint LOCALE_IFIRSTDAYOFWEEK = 0x0000100C; + internal const uint LOCALE_RETURN_NUMBER = 0x20000000; + internal const uint LOCALE_NOUSEROVERRIDE = 0x80000000; + internal const int COMPARE_STRING = 0x0001; + internal const uint TIME_NOSECONDS = 0x00000002; + + internal const string LOCALE_NAME_USER_DEFAULT = null; + internal const string LOCALE_NAME_SYSTEM_DEFAULT = "!x-sys-default-locale"; + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern unsafe int LCIDToLocaleName(int locale, char *pLocaleName, int cchName, uint dwFlags); diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 9a430b6..ea3c7cc 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -243,6 +243,7 @@ + diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs index de50374..3702ee4 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs @@ -455,13 +455,9 @@ namespace System.Globalization { Debug.Assert(!GlobalizationMode.Invariant); - const int LOCALE_NAME_MAX_LENGTH = 85; - const uint LOCALE_SNAME = 0x0000005c; - const string LOCALE_NAME_USER_DEFAULT = null; - int result; - char* localeName = stackalloc char[LOCALE_NAME_MAX_LENGTH]; - result = CultureData.GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, localeName, LOCALE_NAME_MAX_LENGTH); + char* localeName = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH]; + result = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_USER_DEFAULT, Interop.Kernel32.LOCALE_SNAME, localeName, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH); return result <= 0 ? "" : new string(localeName, 0, result - 1); // exclude the null termination } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs index 4f51269..e627cc7 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs @@ -2,16 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -//////////////////////////////////////////////////////////////////////////// -// -// -// Purpose: This class implements a set of methods for retrieving -// character type information. Character type information is -// independent of culture and region. -// -// -//////////////////////////////////////////////////////////////////////////// - using System.Buffers.Binary; using System.Diagnostics; using System.Text; @@ -19,15 +9,13 @@ using Internal.Runtime.CompilerServices; namespace System.Globalization { + /// + /// This class implements a set of methods for retrieving character type + /// information. Character type information is independent of culture + /// and region. + /// public static partial class CharUnicodeInfo { - //--------------------------------------------------------------------// - // Internal Information // - //--------------------------------------------------------------------// - - // - // Native methods to access the Unicode category data tables in charinfo.nlp. - // internal const char HIGH_SURROGATE_START = '\ud800'; internal const char HIGH_SURROGATE_END = '\udbff'; internal const char LOW_SURROGATE_START = '\udc00'; @@ -40,19 +28,14 @@ namespace System.Globalization // The starting codepoint for Unicode plane 1. Plane 1 contains 0x010000 ~ 0x01ffff. internal const int UNICODE_PLANE01_START = 0x10000; - - //////////////////////////////////////////////////////////////////////// - // - // Actions: - // Convert the BMP character or surrogate pointed by index to a UTF32 value. - // This is similar to char.ConvertToUTF32, but the difference is that - // it does not throw exceptions when invalid surrogate characters are passed in. - // - // WARNING: since it doesn't throw an exception it CAN return a value - // in the surrogate range D800-DFFF, which are not legal unicode values. - // - //////////////////////////////////////////////////////////////////////// - + /// + /// Convert the BMP character or surrogate pointed by index to a UTF32 value. + /// This is similar to char.ConvertToUTF32, but the difference is that + /// it does not throw exceptions when invalid surrogate characters are passed in. + /// + /// WARNING: since it doesn't throw an exception it CAN return a value + /// in the surrogate range D800-DFFF, which are not legal unicode values. + /// internal static int InternalConvertToUtf32(string s, int index) { Debug.Assert(s != null, "s != null"); @@ -70,7 +53,7 @@ namespace System.Globalization } } } - return ((int)s[index]); + return (int)s[index]; } internal static int InternalConvertToUtf32(StringBuilder s, int index) @@ -88,35 +71,19 @@ namespace System.Globalization if ((uint)temp2 <= HIGH_SURROGATE_RANGE) { // Convert the surrogate to UTF32 and get the result. - return ((temp1 * 0x400) + temp2 + UNICODE_PLANE01_START); + return (temp1 * 0x400) + temp2 + UNICODE_PLANE01_START; } } } return c; } - //////////////////////////////////////////////////////////////////////// - // - // Convert a character or a surrogate pair starting at index of string s - // to UTF32 value. - // - // Parameters: - // s The string - // index The starting index. It can point to a BMP character or - // a surrogate pair. - // len The length of the string. - // charLength [out] If the index points to a BMP char, charLength - // will be 1. If the index points to a surrogate pair, - // charLength will be 2. - // - // WARNING: since it doesn't throw an exception it CAN return a value - // in the surrogate range D800-DFFF, which are not legal unicode values. - // - // Returns: - // The UTF32 value - // - //////////////////////////////////////////////////////////////////////// - + /// + /// Convert a character or a surrogate pair starting at index of string s + /// to UTF32 value. + /// WARNING: since it doesn't throw an exception it CAN return a value + /// in the surrogate range D800-DFFF, which are not legal unicode values. + /// internal static int InternalConvertToUtf32(string s, int index, out int charLength) { Debug.Assert(s != null, "s != null"); @@ -140,10 +107,11 @@ namespace System.Globalization return ((int)s[index]); } - // - // This is called by the public char and string, index versions - // - // Note that for ch in the range D800-DFFF we just treat it as any other non-numeric character + /// + /// This is called by the public char and string, index versions + /// Note that for ch in the range D800-DFFF we just treat it as any + /// other non-numeric character + /// internal static double InternalGetNumericValue(int ch) { Debug.Assert(ch >= 0 && ch <= 0x10ffff, "ch is not in valid Unicode range."); @@ -159,7 +127,10 @@ namespace System.Globalization ref var value = ref Unsafe.AsRef(in NumericValues[index * 8]); if (BitConverter.IsLittleEndian) + { return Unsafe.ReadUnaligned(ref value); + } + return BitConverter.Int64BitsToDouble(BinaryPrimitives.ReverseEndianness(Unsafe.ReadUnaligned(ref value))); } return -1; @@ -182,28 +153,17 @@ namespace System.Globalization return 0xff; } - //////////////////////////////////////////////////////////////////////// - // - //Returns the numeric value associated with the character c. If the character is a fraction, - // the return value will not be an integer. If the character does not have a numeric value, the return value is -1. - // - //Returns: - // the numeric value for the specified Unicode character. If the character does not have a numeric value, the return value is -1. - //Arguments: - // ch a Unicode character - //Exceptions: - // ArgumentNullException - // ArgumentOutOfRangeException - // - //////////////////////////////////////////////////////////////////////// - - + /// + /// Returns the numeric value associated with the character c. + /// If the character is a fraction, the return value will not be an + /// integer. If the character does not have a numeric value, the return + /// value is -1. + /// public static double GetNumericValue(char ch) { - return (InternalGetNumericValue(ch)); + return InternalGetNumericValue(ch); } - public static double GetNumericValue(string s, int index) { if (s == null) @@ -214,7 +174,8 @@ namespace System.Globalization { throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); } - return (InternalGetNumericValue(InternalConvertToUtf32(s, index))); + + return InternalGetNumericValue(InternalConvertToUtf32(s, index)); } public static int GetDecimalDigitValue(char ch) @@ -228,7 +189,6 @@ namespace System.Globalization { throw new ArgumentNullException(nameof(s)); } - if (index < 0 || index >= s.Length) { throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); @@ -248,7 +208,6 @@ namespace System.Globalization { throw new ArgumentNullException(nameof(s)); } - if (index < 0 || index >= s.Length) { throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); @@ -259,40 +218,32 @@ namespace System.Globalization public static UnicodeCategory GetUnicodeCategory(char ch) { - return (GetUnicodeCategory((int)ch)); + return GetUnicodeCategory((int)ch); } public static UnicodeCategory GetUnicodeCategory(string s, int index) { if (s == null) + { throw new ArgumentNullException(nameof(s)); + } if (((uint)index) >= ((uint)s.Length)) { throw new ArgumentOutOfRangeException(nameof(index)); } + return InternalGetUnicodeCategory(s, index); } public static UnicodeCategory GetUnicodeCategory(int codePoint) { - return ((UnicodeCategory)InternalGetCategoryValue(codePoint, UNICODE_CATEGORY_OFFSET)); + return (UnicodeCategory)InternalGetCategoryValue(codePoint, UNICODE_CATEGORY_OFFSET); } - - //////////////////////////////////////////////////////////////////////// - // - //Action: Returns the Unicode Category property for the character c. - //Returns: - // an value in UnicodeCategory enum - //Arguments: - // ch a Unicode character - //Exceptions: - // None - // - //Note that this API will return values for D800-DF00 surrogate halves. - // - //////////////////////////////////////////////////////////////////////// - + /// + /// Returns the Unicode Category property for the character c. + /// Note that this API will return values for D800-DF00 surrogate halves. + /// internal static byte InternalGetCategoryValue(int ch, int offset) { Debug.Assert(ch >= 0 && ch <= 0x10ffff, "ch is not in valid Unicode range."); @@ -302,26 +253,18 @@ namespace System.Globalization // Note that & has the lower precedence than addition, so don't forget the parathesis. index = Unsafe.ReadUnaligned(ref Unsafe.AsRef(in CategoryLevel2Index[(index << 6) + ((ch >> 3) & 0b111110)])); if (!BitConverter.IsLittleEndian) + { index = BinaryPrimitives.ReverseEndianness((ushort)index); + } // Get the result from the 0 -3 bit of ch. index = CategoryLevel3Index[(index << 4) + (ch & 0x000f)]; return CategoriesValue[index * 2 + offset]; } - //////////////////////////////////////////////////////////////////////// - // - //Action: Returns the Unicode Category property for the character c. - //Returns: - // an value in UnicodeCategory enum - //Arguments: - // value a Unicode String - // index Index for the specified string. - //Exceptions: - // None - // - //////////////////////////////////////////////////////////////////////// - + /// + /// Returns the Unicode Category property for the character c. + /// internal static UnicodeCategory InternalGetUnicodeCategory(string value, int index) { Debug.Assert(value != null, "value can not be null"); @@ -333,8 +276,9 @@ namespace System.Globalization internal static BidiCategory GetBidiCategory(string s, int index) { if (s == null) + { throw new ArgumentNullException(nameof(s)); - + } if (((uint)index) >= ((uint)s.Length)) { throw new ArgumentOutOfRangeException(nameof(index)); @@ -351,20 +295,17 @@ namespace System.Globalization return ((BidiCategory) InternalGetCategoryValue(InternalConvertToUtf32(s, index), BIDI_CATEGORY_OFFSET)); } - //////////////////////////////////////////////////////////////////////// - // - // Get the Unicode category of the character starting at index. If the character is in BMP, charLength will return 1. - // If the character is a valid surrogate pair, charLength will return 2. - // - //////////////////////////////////////////////////////////////////////// - + /// + /// Get the Unicode category of the character starting at index. If the character is in BMP, charLength will return 1. + /// If the character is a valid surrogate pair, charLength will return 2. + /// internal static UnicodeCategory InternalGetUnicodeCategory(string str, int index, out int charLength) { Debug.Assert(str != null, "str can not be null"); Debug.Assert(str.Length > 0, "str.Length > 0"); ; Debug.Assert(index >= 0 && index < str.Length, "index >= 0 && index < str.Length"); - return (GetUnicodeCategory(InternalConvertToUtf32(str, index, out charLength))); + return GetUnicodeCategory(InternalConvertToUtf32(str, index, out charLength)); } internal static bool IsCombiningCategory(UnicodeCategory uc) diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs index 9f7669e..97bb90f 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs @@ -2,18 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -//////////////////////////////////////////////////////////////////////////// -// -// -// -// Purpose: This class implements a set of methods for comparing -// strings. -// -// -//////////////////////////////////////////////////////////////////////////// - -using System.Reflection; using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Text; @@ -21,22 +12,11 @@ using Internal.Runtime.CompilerServices; namespace System.Globalization { - [Flags] - public enum CompareOptions - { - None = 0x00000000, - IgnoreCase = 0x00000001, - IgnoreNonSpace = 0x00000002, - IgnoreSymbols = 0x00000004, - IgnoreKanaType = 0x00000008, // ignore kanatype - IgnoreWidth = 0x00000010, // ignore width - OrdinalIgnoreCase = 0x10000000, // This flag can not be used with other flags. - StringSort = 0x20000000, // use string sort method - Ordinal = 0x40000000, // This flag can not be used with other flags. - } - + /// + /// This class implements a set of methods for comparing strings. + /// [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] + [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public partial class CompareInfo : IDeserializationCallback { // Mask used to check if IndexOf()/LastIndexOf()/IsPrefix()/IsPostfix() has the right flags. @@ -62,7 +42,6 @@ namespace System.Globalization // Cache the invariant CompareInfo internal static readonly CompareInfo Invariant = CultureInfo.InvariantCulture.CompareInfo; - // // CompareInfos have an interesting identity. They are attached to the locale that created them, // ie: en-US would have an en-US sort. For haw-US (custom), then we serialize it as haw-US. // The interesting part is that since haw-US doesn't have its own sort, it has to point at another @@ -84,18 +63,11 @@ namespace System.Globalization InitSort(culture); } - /*=================================GetCompareInfo========================== - **Action: Get the CompareInfo constructed from the data table in the specified assembly for the specified culture. - ** Warning: The assembly versioning mechanism is dead! - **Returns: The CompareInfo for the specified culture. - **Arguments: - ** culture the ID of the culture - ** assembly the assembly which contains the sorting table. - **Exceptions: - ** ArgumentNullException when the assembly is null - ** ArgumentException if culture is invalid. - ============================================================================*/ - // Assembly constructor should be deprecated, we don't act on the assembly information any more + /// + /// Get the CompareInfo constructed from the data table in the specified + /// assembly for the specified culture. + /// Warning: The assembly versioning mechanism is dead! + /// public static CompareInfo GetCompareInfo(int culture, Assembly assembly) { // Parameter checking. @@ -105,69 +77,52 @@ namespace System.Globalization } if (assembly != typeof(object).Module.Assembly) { - throw new ArgumentException(SR.Argument_OnlyMscorlib); + throw new ArgumentException(SR.Argument_OnlyMscorlib, nameof(assembly)); } return GetCompareInfo(culture); } - /*=================================GetCompareInfo========================== - **Action: Get the CompareInfo constructed from the data table in the specified assembly for the specified culture. - ** The purpose of this method is to provide version for CompareInfo tables. - **Returns: The CompareInfo for the specified culture. - **Arguments: - ** name the name of the culture - ** assembly the assembly which contains the sorting table. - **Exceptions: - ** ArgumentNullException when the assembly is null - ** ArgumentException if name is invalid. - ============================================================================*/ - // Assembly constructor should be deprecated, we don't act on the assembly information any more + /// + /// Get the CompareInfo constructed from the data table in the specified + /// assembly for the specified culture. + /// The purpose of this method is to provide version for CompareInfo tables. + /// public static CompareInfo GetCompareInfo(string name, Assembly assembly) { - if (name == null || assembly == null) + if (name == null) { - throw new ArgumentNullException(name == null ? nameof(name) : nameof(assembly)); + throw new ArgumentNullException(nameof(name)); + } + if (assembly == null) + { + throw new ArgumentNullException(nameof(assembly)); } - if (assembly != typeof(object).Module.Assembly) { - throw new ArgumentException(SR.Argument_OnlyMscorlib); + throw new ArgumentException(SR.Argument_OnlyMscorlib, nameof(assembly)); } return GetCompareInfo(name); } - /*=================================GetCompareInfo========================== - **Action: Get the CompareInfo for the specified culture. - ** This method is provided for ease of integration with NLS-based software. - **Returns: The CompareInfo for the specified culture. - **Arguments: - ** culture the ID of the culture. - **Exceptions: - ** ArgumentException if culture is invalid. - ============================================================================*/ - // People really shouldn't be calling LCID versions, no custom support + /// + /// Get the CompareInfo for the specified culture. + /// This method is provided for ease of integration with NLS-based software. + /// public static CompareInfo GetCompareInfo(int culture) { if (CultureData.IsCustomCultureId(culture)) { - // Customized culture cannot be created by the LCID. throw new ArgumentException(SR.Argument_CustomCultureCannotBePassedByNumber, nameof(culture)); } return CultureInfo.GetCultureInfo(culture).CompareInfo; } - /*=================================GetCompareInfo========================== - **Action: Get the CompareInfo for the specified culture. - **Returns: The CompareInfo for the specified culture. - **Arguments: - ** name the name of the culture. - **Exceptions: - ** ArgumentException if name is invalid. - ============================================================================*/ - + /// + /// Get the CompareInfo for the specified culture. + /// public static CompareInfo GetCompareInfo(string name) { if (name == null) @@ -184,6 +139,7 @@ namespace System.Globalization { return true; } + char *pChar = &ch; return IsSortable(pChar, 1); } @@ -192,14 +148,12 @@ namespace System.Globalization { if (text == null) { - // A null param is invalid here. throw new ArgumentNullException(nameof(text)); } if (text.Length == 0) { - // A zero length string is not invalid, but it is also not sortable. - return (false); + return false; } if (GlobalizationMode.Invariant) @@ -236,8 +190,7 @@ namespace System.Globalization if (m_name == null) { // From whidbey, didn't have a name - CultureInfo ci = CultureInfo.GetCultureInfo(this.culture); - m_name = ci._name; + m_name = CultureInfo.GetCultureInfo(culture)._name; } else { @@ -249,22 +202,20 @@ namespace System.Globalization private void OnSerializing(StreamingContext ctx) { // This is merely for serialization compatibility with Whidbey/Orcas, it can go away when we don't want that compat any more. - culture = CultureInfo.GetCultureInfo(this.Name).LCID; // This is the lcid of the constructing culture (still have to dereference to get target sort) + culture = CultureInfo.GetCultureInfo(Name).LCID; // This is the lcid of the constructing culture (still have to dereference to get target sort) Debug.Assert(m_name != null, "CompareInfo.OnSerializing - expected m_name to be set already"); } - ///////////////////////////----- Name -----///////////////////////////////// - // - // Returns the name of the culture (well actually, of the sort). - // Very important for providing a non-LCID way of identifying - // what the sort is. - // - // Note that this name isn't dereferenced in case the CompareInfo is a different locale - // which is consistent with the behaviors of earlier versions. (so if you ask for a sort - // and the locale's changed behavior, then you'll get changed behavior, which is like - // what happens for a version update) - // - //////////////////////////////////////////////////////////////////////// + /// + /// Returns the name of the culture (well actually, of the sort). + /// Very important for providing a non-LCID way of identifying + /// what the sort is. + /// + /// Note that this name isn't dereferenced in case the CompareInfo is a different locale + /// which is consistent with the behaviors of earlier versions. (so if you ask for a sort + /// and the locale's changed behavior, then you'll get changed behavior, which is like + /// what happens for a version update) + /// public virtual string Name { @@ -280,17 +231,12 @@ namespace System.Globalization } } - //////////////////////////////////////////////////////////////////////// - // - // Compare - // - // Compares the two strings with the given options. Returns 0 if the - // two strings are equal, a number less than 0 if string1 is less - // than string2, and a number greater than 0 if string1 is greater - // than string2. - // - //////////////////////////////////////////////////////////////////////// - + /// + /// Compares the two strings with the given options. Returns 0 if the + /// two strings are equal, a number less than 0 if string1 is less + /// than string2, and a number greater than 0 if string1 is greater + /// than string2. + /// public virtual int Compare(string string1, string string2) { return Compare(string1, string2, CompareOptions.None); @@ -319,25 +265,27 @@ namespace System.Globalization throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); } - //Our paradigm is that null sorts less than any other string and - //that two nulls sort as equal. + // Our paradigm is that null sorts less than any other string and + // that two nulls sort as equal. if (string1 == null) { if (string2 == null) { - return (0); // Equal + return 0; } - return (-1); // null < non-null + return -1; // null < non-null } if (string2 == null) { - return (1); // non-null > null + return 1; // non-null > null } if (GlobalizationMode.Invariant) { if ((options & CompareOptions.IgnoreCase) != 0) + { return CompareOrdinalIgnoreCase(string1, string2); + } return string.CompareOrdinal(string1, string2); } @@ -391,7 +339,9 @@ namespace System.Globalization { // Check for empty span or span from a null string if (string1.Length == 0 || string2.Length == 0) + { return string1.Length - string2.Length; + } return GlobalizationMode.Invariant ? string.CompareOrdinal(string1, string2) : @@ -402,56 +352,51 @@ namespace System.Globalization { // Check for empty span or span from a null string if (string1.Length == 0 || string2.Length == 0) + { return string1.Length - string2.Length; + } return GlobalizationMode.Invariant ? CompareOrdinalIgnoreCase(string1, string2) : CompareString(string1, string2, CompareOptions.IgnoreCase); } - //////////////////////////////////////////////////////////////////////// - // - // Compare - // - // Compares the specified regions of the two strings with the given - // options. - // Returns 0 if the two strings are equal, a number less than 0 if - // string1 is less than string2, and a number greater than 0 if - // string1 is greater than string2. - // - //////////////////////////////////////////////////////////////////////// - - + /// + /// Compares the specified regions of the two strings with the given + /// options. + /// Returns 0 if the two strings are equal, a number less than 0 if + /// string1 is less than string2, and a number greater than 0 if + /// string1 is greater than string2. + /// public virtual int Compare(string string1, int offset1, int length1, string string2, int offset2, int length2) { return Compare(string1, offset1, length1, string2, offset2, length2, 0); } - public virtual int Compare(string string1, int offset1, string string2, int offset2, CompareOptions options) { return Compare(string1, offset1, string1 == null ? 0 : string1.Length - offset1, string2, offset2, string2 == null ? 0 : string2.Length - offset2, options); } - public virtual int Compare(string string1, int offset1, string string2, int offset2) { return Compare(string1, offset1, string2, offset2, 0); } - public virtual int Compare(string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options) { if (options == CompareOptions.OrdinalIgnoreCase) { int result = string.Compare(string1, offset1, string2, offset2, length1 < length2 ? length1 : length2, StringComparison.OrdinalIgnoreCase); if ((length1 != length2) && result == 0) - return (length1 > length2 ? 1 : -1); - return (result); + { + return length1 > length2 ? 1 : -1; + } + + return result; } - // Verify inputs if (length1 < 0 || length2 < 0) { throw new ArgumentOutOfRangeException((length1 < 0) ? nameof(length1) : nameof(length2), SR.ArgumentOutOfRange_NeedPosNum); @@ -481,20 +426,17 @@ namespace System.Globalization throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); } - // - // Check for the null case. - // if (string1 == null) { if (string2 == null) { - return (0); + return 0; } - return (-1); + return -1; } if (string2 == null) { - return (1); + return 1; } ReadOnlySpan span1 = string1.AsSpan(offset1, length1); @@ -508,7 +450,9 @@ namespace System.Globalization if (GlobalizationMode.Invariant) { if ((options & CompareOptions.IgnoreCase) != 0) + { return CompareOrdinalIgnoreCase(span1, span2); + } return string.CompareOrdinal(span1, span2); } @@ -516,11 +460,11 @@ namespace System.Globalization return CompareString(span1, span2, options); } - // - // CompareOrdinalIgnoreCase compare two string ordinally with ignoring the case. - // it assumes the strings are Ascii string till we hit non Ascii character in strA or strB and then we continue the comparison by - // calling the OS. - // + /// + /// CompareOrdinalIgnoreCase compare two string ordinally with ignoring the case. + /// it assumes the strings are Ascii string till we hit non Ascii character in strA or strB and then we continue the comparison by + /// calling the OS. + /// internal static int CompareOrdinalIgnoreCase(string strA, int indexA, int lengthA, string strB, int indexB, int lengthB) { Debug.Assert(indexA + lengthA <= strA.Length); @@ -571,9 +515,13 @@ namespace System.Globalization // Uppercase both chars if needed if ((uint)(charA - 'a') <= 'z' - 'a') + { currentA -= 0x20; + } if ((uint)(charB - 'a') <= 'z' - 'a') + { currentB -= 0x20; + } // Return the (case-insensitive) difference between them. return currentA - currentB; @@ -581,7 +529,9 @@ namespace System.Globalization } if (length == 0) + { return lengthA - lengthB; + } Debug.Assert(!GlobalizationMode.Invariant); @@ -730,27 +680,25 @@ namespace System.Globalization } } - //////////////////////////////////////////////////////////////////////// - // - // IsPrefix - // - // Determines whether prefix is a prefix of string. If prefix equals - // string.Empty, true is returned. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Determines whether prefix is a prefix of string. If prefix equals + /// string.Empty, true is returned. + /// public virtual bool IsPrefix(string source, string prefix, CompareOptions options) { - if (source == null || prefix == null) + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + if (prefix == null) { - throw new ArgumentNullException((source == null ? nameof(source) : nameof(prefix)), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(prefix)); } if (prefix.Length == 0) { - return (true); + return true; } - if (source.Length == 0) { return false; @@ -792,30 +740,28 @@ namespace System.Globalization public virtual bool IsPrefix(string source, string prefix) { - return (IsPrefix(source, prefix, 0)); + return IsPrefix(source, prefix, 0); } - //////////////////////////////////////////////////////////////////////// - // - // IsSuffix - // - // Determines whether suffix is a suffix of string. If suffix equals - // string.Empty, true is returned. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Determines whether suffix is a suffix of string. If suffix equals + /// string.Empty, true is returned. + /// public virtual bool IsSuffix(string source, string suffix, CompareOptions options) { - if (source == null || suffix == null) + if (source == null) { - throw new ArgumentNullException((source == null ? nameof(source) : nameof(suffix)), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(source)); + } + if (suffix == null) + { + throw new ArgumentNullException(nameof(suffix)); } if (suffix.Length == 0) { - return (true); + return true; } - if (source.Length == 0) { return false; @@ -855,35 +801,29 @@ namespace System.Globalization return EndsWith(source, suffix, options); } - public virtual bool IsSuffix(string source, string suffix) { - return (IsSuffix(source, suffix, 0)); + return IsSuffix(source, suffix, 0); } - //////////////////////////////////////////////////////////////////////// - // - // IndexOf - // - // Returns the first index where value is found in string. The - // search starts from startIndex and ends at endIndex. Returns -1 if - // the specified value is not found. If value equals string.Empty, - // startIndex is returned. Throws IndexOutOfRange if startIndex or - // endIndex is less than zero or greater than the length of string. - // Throws ArgumentException if value is null. - // - //////////////////////////////////////////////////////////////////////// - - + /// + /// Returns the first index where value is found in string. The + /// search starts from startIndex and ends at endIndex. Returns -1 if + /// the specified value is not found. If value equals string.Empty, + /// startIndex is returned. Throws IndexOutOfRange if startIndex or + /// endIndex is less than zero or greater than the length of string. + /// Throws ArgumentException if value is null. + /// public virtual int IndexOf(string source, char value) { if (source == null) + { throw new ArgumentNullException(nameof(source)); + } return IndexOf(source, value, 0, source.Length, CompareOptions.None); } - public virtual int IndexOf(string source, string value) { if (source == null) @@ -892,20 +832,22 @@ namespace System.Globalization return IndexOf(source, value, 0, source.Length, CompareOptions.None); } - public virtual int IndexOf(string source, char value, CompareOptions options) { if (source == null) + { throw new ArgumentNullException(nameof(source)); + } return IndexOf(source, value, 0, source.Length, options); } - public virtual int IndexOf(string source, string value, CompareOptions options) { if (source == null) + { throw new ArgumentNullException(nameof(source)); + } return IndexOf(source, value, 0, source.Length, options); } @@ -913,7 +855,9 @@ namespace System.Globalization public virtual int IndexOf(string source, char value, int startIndex) { if (source == null) + { throw new ArgumentNullException(nameof(source)); + } return IndexOf(source, value, startIndex, source.Length - startIndex, CompareOptions.None); } @@ -929,21 +873,23 @@ namespace System.Globalization public virtual int IndexOf(string source, char value, int startIndex, CompareOptions options) { if (source == null) + { throw new ArgumentNullException(nameof(source)); + } return IndexOf(source, value, startIndex, source.Length - startIndex, options); } - public virtual int IndexOf(string source, string value, int startIndex, CompareOptions options) { if (source == null) + { throw new ArgumentNullException(nameof(source)); + } return IndexOf(source, value, startIndex, source.Length - startIndex, options); } - public virtual int IndexOf(string source, char value, int startIndex, int count) { return IndexOf(source, value, startIndex, count, CompareOptions.None); @@ -957,15 +903,18 @@ namespace System.Globalization public unsafe virtual int IndexOf(string source, char value, int startIndex, int count, CompareOptions options) { - // Validate inputs if (source == null) + { throw new ArgumentNullException(nameof(source)); - + } if (startIndex < 0 || startIndex > source.Length) + { throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - + } if (count < 0 || startIndex > source.Length - count) + { throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + } if (source.Length == 0) { @@ -975,19 +924,23 @@ namespace System.Globalization // Validate CompareOptions // Ordinal can't be selected with other flags if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal && options != CompareOptions.OrdinalIgnoreCase)) + { throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + } return IndexOf(source, char.ToString(value), startIndex, count, options, null); } public unsafe virtual int IndexOf(string source, string value, int startIndex, int count, CompareOptions options) { - // Validate inputs if (source == null) + { throw new ArgumentNullException(nameof(source)); + } if (value == null) + { throw new ArgumentNullException(nameof(value)); - + } if (startIndex > source.Length) { throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); @@ -1010,12 +963,16 @@ namespace System.Globalization } if (count < 0 || startIndex > source.Length - count) + { throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + } // Validate CompareOptions // Ordinal can't be selected with other flags if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal && options != CompareOptions.OrdinalIgnoreCase)) + { throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + } return IndexOf(source, value, startIndex, count, options, null); } @@ -1053,8 +1010,10 @@ namespace System.Globalization return IndexOfCore(source, value, options, null, fromBeginning: false); } - // The following IndexOf overload is mainly used by String.Replace. This overload assumes the parameters are already validated - // and the caller is passing a valid matchLengthPtr pointer. + /// + /// The following IndexOf overload is mainly used by String.Replace. This overload assumes the parameters are already validated + /// and the caller is passing a valid matchLengthPtr pointer. + /// internal unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options, int* matchLengthPtr) { Debug.Assert(source != null); @@ -1108,7 +1067,9 @@ namespace System.Globalization { retValue += startIndex; if (matchLengthPtr != null) + { *matchLengthPtr = value.Length; + } } return retValue; @@ -1140,24 +1101,20 @@ namespace System.Globalization return IndexOfOrdinalCore(source, value, startIndex, count, ignoreCase); } - //////////////////////////////////////////////////////////////////////// - // - // LastIndexOf - // - // Returns the last index where value is found in string. The - // search starts from startIndex and ends at endIndex. Returns -1 if - // the specified value is not found. If value equals string.Empty, - // endIndex is returned. Throws IndexOutOfRange if startIndex or - // endIndex is less than zero or greater than the length of string. - // Throws ArgumentException if value is null. - // - //////////////////////////////////////////////////////////////////////// - - + /// + /// Returns the last index where value is found in string. The + /// search starts from startIndex and ends at endIndex. Returns -1 if + /// the specified value is not found. If value equals string.Empty, + /// endIndex is returned. Throws IndexOutOfRange if startIndex or + /// endIndex is less than zero or greater than the length of string. + /// Throws ArgumentException if value is null. + /// public virtual int LastIndexOf(string source, char value) { if (source == null) + { throw new ArgumentNullException(nameof(source)); + } // Can't start at negative index, so make sure we check for the length == 0 case. return LastIndexOf(source, value, source.Length - 1, source.Length, CompareOptions.None); @@ -1167,7 +1124,9 @@ namespace System.Globalization public virtual int LastIndexOf(string source, string value) { if (source == null) + { throw new ArgumentNullException(nameof(source)); + } // Can't start at negative index, so make sure we check for the length == 0 case. return LastIndexOf(source, value, source.Length - 1, @@ -1178,17 +1137,20 @@ namespace System.Globalization public virtual int LastIndexOf(string source, char value, CompareOptions options) { if (source == null) + { throw new ArgumentNullException(nameof(source)); + } // Can't start at negative index, so make sure we check for the length == 0 case. - return LastIndexOf(source, value, source.Length - 1, - source.Length, options); + return LastIndexOf(source, value, source.Length - 1, source.Length, options); } public virtual int LastIndexOf(string source, string value, CompareOptions options) { if (source == null) + { throw new ArgumentNullException(nameof(source)); + } // Can't start at negative index, so make sure we check for the length == 0 case. return LastIndexOf(source, value, source.Length - 1, source.Length, options); @@ -1199,7 +1161,6 @@ namespace System.Globalization return LastIndexOf(source, value, startIndex, startIndex + 1, CompareOptions.None); } - public virtual int LastIndexOf(string source, string value, int startIndex) { return LastIndexOf(source, value, startIndex, startIndex + 1, CompareOptions.None); @@ -1210,57 +1171,63 @@ namespace System.Globalization return LastIndexOf(source, value, startIndex, startIndex + 1, options); } - public virtual int LastIndexOf(string source, string value, int startIndex, CompareOptions options) { return LastIndexOf(source, value, startIndex, startIndex + 1, options); } - public virtual int LastIndexOf(string source, char value, int startIndex, int count) { return LastIndexOf(source, value, startIndex, count, CompareOptions.None); } - public virtual int LastIndexOf(string source, string value, int startIndex, int count) { return LastIndexOf(source, value, startIndex, count, CompareOptions.None); } - public virtual int LastIndexOf(string source, char value, int startIndex, int count, CompareOptions options) { - // Verify Arguments if (source == null) + { throw new ArgumentNullException(nameof(source)); - + } // Validate CompareOptions // Ordinal can't be selected with other flags if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal) && (options != CompareOptions.OrdinalIgnoreCase)) + { throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + } // Special case for 0 length input strings if (source.Length == 0 && (startIndex == -1 || startIndex == 0)) + { return -1; + } // Make sure we're not out of range if (startIndex < 0 || startIndex > source.Length) + { throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + } // Make sure that we allow startIndex == source.Length if (startIndex == source.Length) { startIndex--; if (count > 0) + { count--; + } } // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0. if (count < 0 || startIndex - count + 1 < 0) + { throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + } if (options == CompareOptions.OrdinalIgnoreCase) { @@ -1268,19 +1235,23 @@ namespace System.Globalization } if (GlobalizationMode.Invariant) + { return InvariantLastIndexOf(source, char.ToString(value), startIndex, count, (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0); + } return LastIndexOfCore(source, value.ToString(), startIndex, count, options); } - public virtual int LastIndexOf(string source, string value, int startIndex, int count, CompareOptions options) { - // Verify Arguments if (source == null) + { throw new ArgumentNullException(nameof(source)); + } if (value == null) + { throw new ArgumentNullException(nameof(value)); + } // Validate CompareOptions // Ordinal can't be selected with other flags @@ -1291,27 +1262,37 @@ namespace System.Globalization // Special case for 0 length input strings if (source.Length == 0 && (startIndex == -1 || startIndex == 0)) + { return (value.Length == 0) ? 0 : -1; + } // Make sure we're not out of range if (startIndex < 0 || startIndex > source.Length) + { throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + } // Make sure that we allow startIndex == source.Length if (startIndex == source.Length) { startIndex--; if (count > 0) + { count--; + } // If we are looking for nothing, just return 0 if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0) + { return startIndex; + } } // 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0. if (count < 0 || startIndex - count + 1 < 0) + { throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + } if (options == CompareOptions.OrdinalIgnoreCase) { @@ -1334,17 +1315,15 @@ namespace System.Globalization return LastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase); } - //////////////////////////////////////////////////////////////////////// - // - // GetSortKey - // - // Gets the SortKey for the given string with the given options. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Gets the SortKey for the given string with the given options. + /// public virtual SortKey GetSortKey(string source, CompareOptions options) { if (GlobalizationMode.Invariant) + { return InvariantCreateSortKey(source, options); + } return CreateSortKey(source, options); } @@ -1353,86 +1332,50 @@ namespace System.Globalization public virtual SortKey GetSortKey(string source) { if (GlobalizationMode.Invariant) + { return InvariantCreateSortKey(source, CompareOptions.None); + } return CreateSortKey(source, CompareOptions.None); } - //////////////////////////////////////////////////////////////////////// - // - // Equals - // - // Implements Object.Equals(). Returns a boolean indicating whether - // or not object refers to the same CompareInfo as the current - // instance. - // - //////////////////////////////////////////////////////////////////////// - - public override bool Equals(object value) { - if (value is CompareInfo that) - { - return this.Name == that.Name; - } - - return (false); - } - - - //////////////////////////////////////////////////////////////////////// - // - // GetHashCode - // - // Implements Object.GetHashCode(). Returns the hash code for the - // CompareInfo. The hash code is guaranteed to be the same for - // CompareInfo A and B where A.Equals(B) is true. - // - //////////////////////////////////////////////////////////////////////// - - - public override int GetHashCode() - { - return (this.Name.GetHashCode()); - } - - //////////////////////////////////////////////////////////////////////// - // - // GetHashCodeOfString - // - // This internal method allows a method that allows the equivalent of creating a Sortkey for a - // string from CompareInfo, and generate a hashcode value from it. It is not very convenient - // to use this method as is and it creates an unnecessary Sortkey object that will be GC'ed. - // - // The hash code is guaranteed to be the same for string A and B where A.Equals(B) is true and both - // the CompareInfo and the CompareOptions are the same. If two different CompareInfo objects - // treat the string the same way, this implementation will treat them differently (the same way that - // Sortkey does at the moment). - // - // This method will never be made public itself, but public consumers of it could be created, e.g.: - // - // string.GetHashCode(CultureInfo) - // string.GetHashCode(CompareInfo) - // string.GetHashCode(CultureInfo, CompareOptions) - // string.GetHashCode(CompareInfo, CompareOptions) - // etc. - // - // (the methods above that take a CultureInfo would use CultureInfo.CompareInfo) - // - //////////////////////////////////////////////////////////////////////// + return value is CompareInfo otherCompareInfo + && Name == otherCompareInfo.Name; + } + + public override int GetHashCode() => Name.GetHashCode(); + + /// + /// This internal method allows a method that allows the equivalent of creating a Sortkey for a + /// string from CompareInfo, and generate a hashcode value from it. It is not very convenient + /// to use this method as is and it creates an unnecessary Sortkey object that will be GC'ed. + /// + /// The hash code is guaranteed to be the same for string A and B where A.Equals(B) is true and both + /// the CompareInfo and the CompareOptions are the same. If two different CompareInfo objects + /// treat the string the same way, this implementation will treat them differently (the same way that + /// Sortkey does at the moment). + /// + /// This method will never be made public itself, but public consumers of it could be created, e.g.: + /// + /// string.GetHashCode(CultureInfo) + /// string.GetHashCode(CompareInfo) + /// string.GetHashCode(CultureInfo, CompareOptions) + /// string.GetHashCode(CompareInfo, CompareOptions) + /// etc. + /// + /// (the methods above that take a CultureInfo would use CultureInfo.CompareInfo) + /// internal int GetHashCodeOfString(string source, CompareOptions options) { - // - // Parameter validation - // - if (null == source) + if (source == null) { throw new ArgumentNullException(nameof(source)); } if ((options & ValidHashCodeOfStringMaskOffFlags) == 0) { // No unsupported flags are set - continue on with the regular logic - if (GlobalizationMode.Invariant) { return ((options & CompareOptions.IgnoreCase) != 0) ? source.GetHashCodeOrdinalIgnoreCase() : source.GetHashCode(); @@ -1465,13 +1408,9 @@ namespace System.Globalization public int GetHashCode(ReadOnlySpan source, CompareOptions options) { - // - // Parameter validation - // if ((options & ValidHashCodeOfStringMaskOffFlags) == 0) { // No unsupported flags are set - continue on with the regular logic - if (GlobalizationMode.Invariant) { return ((options & CompareOptions.IgnoreCase) != 0) ? string.GetHashCodeOrdinalIgnoreCase(source) : string.GetHashCode(source); @@ -1496,18 +1435,7 @@ namespace System.Globalization } } - //////////////////////////////////////////////////////////////////////// - // - // ToString - // - // Implements Object.ToString(). Returns a string describing the - // CompareInfo. - // - //////////////////////////////////////////////////////////////////////// - public override string ToString() - { - return ("CompareInfo - " + this.Name); - } + public override string ToString() => "CompareInfo - " + Name; public SortVersion Version { @@ -1533,12 +1461,6 @@ namespace System.Globalization } } - public int LCID - { - get - { - return CultureInfo.GetCultureInfo(Name).LCID; - } - } + public int LCID => CultureInfo.GetCultureInfo(Name).LCID; } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CompareOptions.cs b/src/System.Private.CoreLib/shared/System/Globalization/CompareOptions.cs new file mode 100644 index 0000000..366ece4 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Globalization/CompareOptions.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Globalization +{ + [Flags] + public enum CompareOptions + { + None = 0x00000000, + IgnoreCase = 0x00000001, + IgnoreNonSpace = 0x00000002, + IgnoreSymbols = 0x00000004, + IgnoreKanaType = 0x00000008, + IgnoreWidth = 0x00000010, + OrdinalIgnoreCase = 0x10000000, // This flag can not be used with other flags. + StringSort = 0x20000000, + Ordinal = 0x40000000, // This flag can not be used with other flags. + } +} diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs index c800c48..57226ff 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs @@ -69,18 +69,18 @@ namespace System.Globalization } _sRealName = _sName; - _iLanguage = this.ILANGUAGE; + _iLanguage = LCID; if (_iLanguage == 0) { _iLanguage = CultureInfo.LOCALE_CUSTOM_UNSPECIFIED; } - _bNeutral = (this.SISO3166CTRYNAME.Length == 0); + _bNeutral = TwoLetterISOCountryName.Length == 0; _sSpecificCulture = _bNeutral ? LocaleData.GetSpecificCultureName(_sRealName) : _sRealName; // Remove the sort from sName unless custom culture - if (index>0 && !_bNeutral && !IsCustomCultureId(_iLanguage)) + if (index > 0 && !_bNeutral && !IsCustomCultureId(_iLanguage)) { _sName = _sWindowsName.Substring(0, index); } @@ -196,10 +196,7 @@ namespace System.Globalization return new int[] { primaryGroupingSize, secondaryGroupingSize }; } - private string GetTimeFormatString() - { - return GetTimeFormatString(false); - } + private string GetTimeFormatString() => GetTimeFormatString(shortFormat: false); private unsafe string GetTimeFormatString(bool shortFormat) { @@ -219,10 +216,7 @@ namespace System.Globalization return ConvertIcuTimeFormatString(span.Slice(0, span.IndexOf('\0'))); } - private int GetFirstDayOfWeek() - { - return this.GetLocaleInfo(LocaleNumberData.FirstDayOfWeek); - } + private int GetFirstDayOfWeek() => GetLocaleInfo(LocaleNumberData.FirstDayOfWeek); private string[] GetTimeFormats() { @@ -318,31 +312,31 @@ namespace System.Globalization private static int GetAnsiCodePage(string cultureName) { int ansiCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.AnsiCodePage); - return ansiCodePage == -1 ? CultureData.Invariant.IDEFAULTANSICODEPAGE : ansiCodePage; + return ansiCodePage == -1 ? CultureData.Invariant.ANSICodePage : ansiCodePage; } private static int GetOemCodePage(string cultureName) { int oemCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.OemCodePage); - return oemCodePage == -1 ? CultureData.Invariant.IDEFAULTOEMCODEPAGE : oemCodePage; + return oemCodePage == -1 ? CultureData.Invariant.OEMCodePage : oemCodePage; } private static int GetMacCodePage(string cultureName) { int macCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.MacCodePage); - return macCodePage == -1 ? CultureData.Invariant.IDEFAULTMACCODEPAGE : macCodePage; + return macCodePage == -1 ? CultureData.Invariant.MacCodePage : macCodePage; } private static int GetEbcdicCodePage(string cultureName) { int ebcdicCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.EbcdicCodePage); - return ebcdicCodePage == -1 ? CultureData.Invariant.IDEFAULTEBCDICCODEPAGE : ebcdicCodePage; + return ebcdicCodePage == -1 ? CultureData.Invariant.EBCDICCodePage : ebcdicCodePage; } private static int GetGeoId(string cultureName) { int geoId = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.GeoId); - return geoId == -1 ? CultureData.Invariant.IGEOID : geoId; + return geoId == -1 ? CultureData.Invariant.GeoId : geoId; } private static int GetDigitSubstitution(string cultureName) @@ -413,19 +407,10 @@ namespace System.Globalization return LocaleData.GetConsoleUICulture(cultureName); } - internal bool IsFramework // not applicable on Linux based systems - { - get { return false; } - } + internal bool IsFramework => false; - internal bool IsWin32Installed // not applicable on Linux based systems - { - get { return false; } - } + internal bool IsWin32Installed => false; - internal bool IsReplacementCulture // not applicable on Linux based systems - { - get { return false; } - } + internal bool IsReplacementCulture => false; } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs index 75f7862..151f771 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs @@ -17,12 +17,6 @@ namespace System.Globalization { internal partial class CultureData { - private const uint LOCALE_NOUSEROVERRIDE = 0x80000000; - private const uint LOCALE_RETURN_NUMBER = 0x20000000; - private const uint LOCALE_SISO3166CTRYNAME = 0x0000005A; - - private const uint TIME_NOSECONDS = 0x00000002; - /// /// Check with the OS to see if this is a valid culture. /// If so we populate a limited number of fields. If its not valid we return false. @@ -60,15 +54,11 @@ namespace System.Globalization { Debug.Assert(!GlobalizationMode.Invariant); - const uint LOCALE_ILANGUAGE = 0x00000001; - const uint LOCALE_INEUTRAL = 0x00000071; - const uint LOCALE_SNAME = 0x0000005c; - int result; string realNameBuffer = _sRealName; - char* pBuffer = stackalloc char[LOCALE_NAME_MAX_LENGTH]; + char* pBuffer = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH]; - result = GetLocaleInfoEx(realNameBuffer, LOCALE_SNAME, pBuffer, LOCALE_NAME_MAX_LENGTH); + result = GetLocaleInfoEx(realNameBuffer, Interop.Kernel32.LOCALE_SNAME, pBuffer, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH); // Did it fail? if (result == 0) @@ -85,7 +75,7 @@ namespace System.Globalization // Check for neutrality, don't expect to fail // (buffer has our name in it, so we don't have to do the gc. stuff) - result = GetLocaleInfoEx(realNameBuffer, LOCALE_INEUTRAL | LOCALE_RETURN_NUMBER, pBuffer, sizeof(int) / sizeof(char)); + result = GetLocaleInfoEx(realNameBuffer, Interop.Kernel32.LOCALE_INEUTRAL | Interop.Kernel32.LOCALE_RETURN_NUMBER, pBuffer, sizeof(int) / sizeof(char)); if (result == 0) { return false; @@ -110,7 +100,7 @@ namespace System.Globalization // Specific locale name is whatever ResolveLocaleName (win7+) returns. // (Buffer has our name in it, and we can recycle that because windows resolves it before writing to the buffer) - result = Interop.Kernel32.ResolveLocaleName(realNameBuffer, pBuffer, LOCALE_NAME_MAX_LENGTH); + result = Interop.Kernel32.ResolveLocaleName(realNameBuffer, pBuffer, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH); // 0 is failure, 1 is invariant (""), which we expect if (result < 1) @@ -138,7 +128,7 @@ namespace System.Globalization // If we are an alt sort locale then this is the same as the part before the _ in the windows name // This is for like de-DE_phoneb and es-ES_tradnl that hsouldn't have the _ part - result = GetLocaleInfoEx(realNameBuffer, LOCALE_ILANGUAGE | LOCALE_RETURN_NUMBER, pBuffer, sizeof(int) / sizeof(char)); + result = GetLocaleInfoEx(realNameBuffer, Interop.Kernel32.LOCALE_ILANGUAGE | Interop.Kernel32.LOCALE_RETURN_NUMBER, pBuffer, sizeof(int) / sizeof(char)); if (result == 0) { return false; @@ -180,8 +170,7 @@ namespace System.Globalization internal static unsafe int GetLocaleInfoExInt(string localeName, uint field) { - const uint LOCALE_RETURN_NUMBER = 0x20000000; - field |= LOCALE_RETURN_NUMBER; + field |= Interop.Kernel32.LOCALE_RETURN_NUMBER; int value = 0; GetLocaleInfoEx(localeName, field, (char*) &value, sizeof(int)); return value; @@ -216,7 +205,7 @@ namespace System.Globalization // Fix lctype if we don't want overrides if (!UseUserOverride) { - lctype |= LOCALE_NOUSEROVERRIDE; + lctype |= Interop.Kernel32.LOCALE_NOUSEROVERRIDE; } // Ask OS for data, note that we presume it returns success, so we have to know that @@ -232,18 +221,14 @@ namespace System.Globalization private string GetTimeFormatString() { - const uint LOCALE_STIMEFORMAT = 0x00001003; - - return ReescapeWin32String(GetLocaleInfoFromLCType(_sWindowsName, LOCALE_STIMEFORMAT, UseUserOverride)); + return ReescapeWin32String(GetLocaleInfoFromLCType(_sWindowsName, Interop.Kernel32.LOCALE_STIMEFORMAT, UseUserOverride)); } private int GetFirstDayOfWeek() { Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); - const uint LOCALE_IFIRSTDAYOFWEEK = 0x0000100C; - - int result = GetLocaleInfoExInt(_sWindowsName, LOCALE_IFIRSTDAYOFWEEK | (!UseUserOverride ? LOCALE_NOUSEROVERRIDE : 0)); + int result = GetLocaleInfoExInt(_sWindowsName, Interop.Kernel32.LOCALE_IFIRSTDAYOFWEEK | (!UseUserOverride ? Interop.Kernel32.LOCALE_NOUSEROVERRIDE : 0)); // Win32 and .NET disagree on the numbering for days of the week, so we have to convert. return ConvertFirstDayOfWeekMonToSun(result); @@ -262,7 +247,7 @@ namespace System.Globalization { // Note that this gets overrides for us all the time Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected _sWindowsName to be populated by already"); - string[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, TIME_NOSECONDS, UseUserOverride)); + string[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, Interop.Kernel32.TIME_NOSECONDS, UseUserOverride)); return result; } @@ -274,16 +259,13 @@ namespace System.Globalization Debug.Assert(!GlobalizationMode.Invariant); Debug.Assert(regionName != null); - const uint LOCALE_SUPPLEMENTAL = 0x00000002; - const uint LOCALE_SPECIFICDATA = 0x00000020; - EnumLocaleData context = new EnumLocaleData(); context.cultureName = null; context.regionName = regionName; unsafe { - Interop.Kernel32.EnumSystemLocalesEx(EnumSystemLocalesProc, LOCALE_SPECIFICDATA | LOCALE_SUPPLEMENTAL, Unsafe.AsPointer(ref context), IntPtr.Zero); + Interop.Kernel32.EnumSystemLocalesEx(EnumSystemLocalesProc, Interop.Kernel32.LOCALE_SPECIFICDATA | Interop.Kernel32.LOCALE_SUPPLEMENTAL, Unsafe.AsPointer(ref context), IntPtr.Zero); } if (context.cultureName != null) @@ -308,7 +290,7 @@ namespace System.Globalization ((ci = GetUserDefaultCulture()) != null) && !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) { - return SNATIVEDISPLAYNAME; + return NativeName; } else { @@ -329,7 +311,7 @@ namespace System.Globalization return GetLocaleInfo(LocaleStringData.LocalizedCountryName); } - return SNATIVECOUNTRY; + return NativeCountryName; #endif // ENABLE_WINRT } @@ -351,7 +333,7 @@ namespace System.Globalization // Fix lctype if we don't want overrides if (!useUserOveride) { - lctype |= LOCALE_NOUSEROVERRIDE; + lctype |= Interop.Kernel32.LOCALE_NOUSEROVERRIDE; } // Ask OS for data @@ -365,25 +347,26 @@ namespace System.Globalization return result; } - //////////////////////////////////////////////////////////////////////////// - // - // Reescape a Win32 style quote string as a NLS+ style quoted string - // - // This is also the escaping style used by custom culture data files - // - // NLS+ uses \ to escape the next character, whether in a quoted string or - // not, so we always have to change \ to \\. - // - // NLS+ uses \' to escape a quote inside a quoted string so we have to change - // '' to \' (if inside a quoted string) - // - // We don't build the stringbuilder unless we find something to change - //////////////////////////////////////////////////////////////////////////// + /// + /// Reescape a Win32 style quote string as a NLS+ style quoted string + /// + /// This is also the escaping style used by custom culture data files + /// + /// NLS+ uses \ to escape the next character, whether in a quoted string or + /// not, so we always have to change \ to \\. + /// + /// NLS+ uses \' to escape a quote inside a quoted string so we have to change + /// '' to \' (if inside a quoted string) + /// + /// We don't build the stringbuilder unless we find something to change + /// internal static string ReescapeWin32String(string str) { // If we don't have data, then don't try anything if (str == null) + { return null; + } StringBuilder result = null; @@ -531,7 +514,7 @@ namespace System.Globalization try { string cultureName = new string(lpLocaleString); - string regionName = GetLocaleInfoEx(cultureName, LOCALE_SISO3166CTRYNAME); + string regionName = GetLocaleInfoEx(cultureName, Interop.Kernel32.LOCALE_SISO3166CTRYNAME); if (regionName != null && regionName.Equals(context.regionName, StringComparison.OrdinalIgnoreCase)) { context.cultureName = cultureName; @@ -586,9 +569,6 @@ namespace System.Globalization private static unsafe string[] nativeEnumTimeFormats(string localeName, uint dwFlags, bool useUserOverride) { - const uint LOCALE_SSHORTTIME = 0x00000079; - const uint LOCALE_STIMEFORMAT = 0x00001003; - EnumData data = new EnumData(); data.strings = new List(); @@ -608,7 +588,7 @@ namespace System.Globalization // If we do have an override, we don't know if it is a user defined override or if the // user has just selected one of the predefined formats so we can't just remove it // but we can move it down. - uint lcType = (dwFlags == TIME_NOSECONDS) ? LOCALE_SSHORTTIME : LOCALE_STIMEFORMAT; + uint lcType = (dwFlags == Interop.Kernel32.TIME_NOSECONDS) ? Interop.Kernel32.LOCALE_SSHORTTIME : Interop.Kernel32.LOCALE_STIMEFORMAT; string timeFormatNoUserOverride = GetLocaleInfoFromLCType(localeName, lcType, useUserOverride); if (timeFormatNoUserOverride != "") { diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs index 48e0206..1280119 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs @@ -19,40 +19,39 @@ namespace System.Globalization using LcidToCultureNameDictionary = Dictionary; #endif - // - // List of culture data - // Note the we cache overrides. - // Note that localized names (resource names) aren't available from here. - // - - // - // Our names are a tad confusing. - // - // sWindowsName -- The name that windows thinks this culture is, ie: - // en-US if you pass in en-US - // de-DE_phoneb if you pass in de-DE_phoneb - // fj-FJ if you pass in fj (neutral, on a pre-Windows 7 machine) - // fj if you pass in fj (neutral, post-Windows 7 machine) - // - // sRealName -- The name you used to construct the culture, in pretty form - // en-US if you pass in EN-us - // en if you pass in en - // de-DE_phoneb if you pass in de-DE_phoneb - // - // sSpecificCulture -- The specific culture for this culture - // en-US for en-US - // en-US for en - // de-DE_phoneb for alt sort - // fj-FJ for fj (neutral) - // - // sName -- The IETF name of this culture (ie: no sort info, could be neutral) - // en-US if you pass in en-US - // en if you pass in en - // de-DE if you pass in de-DE_phoneb - // + /// + /// List of culture data + /// Note the we cache overrides. + /// Note that localized names (resource names) aren't available from here. + /// + /// + /// Our names are a tad confusing. + /// + /// sWindowsName -- The name that windows thinks this culture is, ie: + /// en-US if you pass in en-US + /// de-DE_phoneb if you pass in de-DE_phoneb + /// fj-FJ if you pass in fj (neutral, on a pre-Windows 7 machine) + /// fj if you pass in fj (neutral, post-Windows 7 machine) + /// + /// sRealName -- The name you used to construct the culture, in pretty form + /// en-US if you pass in EN-us + /// en if you pass in en + /// de-DE_phoneb if you pass in de-DE_phoneb + /// + /// sSpecificCulture -- The specific culture for this culture + /// en-US for en-US + /// en-US for en + /// de-DE_phoneb for alt sort + /// fj-FJ for fj (neutral) + /// + /// sName -- The IETF name of this culture (ie: no sort info, could be neutral) + /// en-US if you pass in en-US + /// en if you pass in en + /// de-DE if you pass in de-DE_phoneb + /// internal partial class CultureData { - private const int LOCALE_NAME_MAX_LENGTH = 85; + private const int LocaleNameMaxLength = 85; private const int undef = -1; // Override flag @@ -156,15 +155,17 @@ namespace System.Globalization private bool _bUseOverrides; // use user overrides? private bool _bNeutral; // Flags for the culture (ie: neutral or not right now) - // Region Name to Culture Name mapping table - // (In future would be nice to be in registry or something) - - //Using a property so we avoid creating the dictionary until we need it + /// + /// Region Name to Culture Name mapping table + /// + /// + /// Using a property so we avoid creating the dictionary until we need it + /// private static StringStringDictionary RegionNames { get { - if (s_RegionNames == null) + if (s_regionNames == null) { StringStringDictionary regionNames = new StringStringDictionary(211 /* prime */); @@ -297,16 +298,16 @@ namespace System.Globalization regionNames.Add("ZA", "af-ZA"); regionNames.Add("ZW", "en-ZW"); - s_RegionNames = regionNames; + s_regionNames = regionNames; } - return s_RegionNames; + return s_regionNames; } } // Cache of regions we've already looked up private static volatile StringCultureDataDictionary s_cachedRegions; - private static volatile StringStringDictionary s_RegionNames; + private static volatile StringStringDictionary s_regionNames; internal static CultureData GetCultureDataForRegion(string cultureName, bool useUserOverride) { @@ -316,16 +317,15 @@ namespace System.Globalization return CultureData.Invariant; } - // // First check if GetCultureData() can find it (ie: its a real culture) - // CultureData retVal = GetCultureData(cultureName, useUserOverride); - if (retVal != null && (retVal.IsNeutralCulture == false)) return retVal; + if (retVal != null && !retVal.IsNeutralCulture) + { + return retVal; + } - // // Not a specific culture, perhaps it's region-only name // (Remember this isn't a core clr path where that's not supported) - // // If it was neutral remember that so that RegionInfo() can throw the right exception CultureData neutral = retVal; @@ -351,9 +351,7 @@ namespace System.Globalization } } - // // Not found in the hash table, look it up the hard way - // // If not a valid mapping from the registry we'll have to try the hard coded table if (retVal == null || (retVal.IsNeutralCulture == true)) @@ -432,7 +430,7 @@ namespace System.Globalization if (GlobalizationMode.Invariant) { // in invariant mode we always return invariant culture only from the enumeration - return new CultureInfo[1] { new CultureInfo("") }; + return new CultureInfo[] { new CultureInfo("") }; } #pragma warning restore 618 @@ -548,11 +546,10 @@ namespace System.Globalization return invariant; } - ///////////////////////////////////////////////////////////////////////// - // Build our invariant information - // - // We need an invariant instance, which we build hard-coded - ///////////////////////////////////////////////////////////////////////// + /// + /// Build our invariant information + /// We need an invariant instance, which we build hard-coded + /// internal static CultureData Invariant { get @@ -567,9 +564,6 @@ namespace System.Globalization } private volatile static CultureData s_Invariant; - /////////////// - // Constructors // - /////////////// // Cache of cultures we've already looked up private static volatile StringCultureDataDictionary s_cachedCultures; private static readonly object s_lock = new object(); @@ -630,7 +624,7 @@ namespace System.Globalization isNeutralName = true; int i = 0; - if (name.Length > LOCALE_NAME_MAX_LENGTH) + if (name.Length > LocaleNameMaxLength) { // Theoretically we shouldn't hit this exception. throw new ArgumentException(SR.Format(SR.Argument_InvalidId, nameof(name))); @@ -676,7 +670,9 @@ namespace System.Globalization } if (changed) + { return new string(normalizedName); + } return name; } @@ -685,7 +681,7 @@ namespace System.Globalization { if (GlobalizationMode.Invariant) { - if (cultureName.Length > LOCALE_NAME_MAX_LENGTH || !CultureInfo.VerifyCultureName(cultureName, false)) + if (cultureName.Length > LocaleNameMaxLength || !CultureInfo.VerifyCultureName(cultureName, false)) { return null; } @@ -704,12 +700,9 @@ namespace System.Globalization culture._sRealName = cultureName; // Ask native code if that one's real - if (culture.InitCultureData() == false) + if (!culture.InitCultureData() && !culture.InitCompatibilityCultureData()) { - if (culture.InitCompatibilityCultureData() == false) - { - return null; - } + return null; } return culture; @@ -737,10 +730,11 @@ namespace System.Globalization } _sRealName = fallbackCultureName; - if (InitCultureData() == false) + if (!InitCultureData()) { return false; } + // fixup our data _sName = realCultureName; // the name that goes back to the user _sParent = fallbackCultureName; @@ -748,14 +742,16 @@ namespace System.Globalization return true; } - // We'd rather people use the named version since this doesn't allow custom locales + /// We'd rather people use the named version since this doesn't allow custom locales internal static CultureData GetCultureData(int culture, bool bUseUserOverride) { string localeName = null; CultureData retVal = null; if (culture == CultureInfo.LOCALE_INVARIANT) + { return Invariant; + } if (GlobalizationMode.Invariant) { @@ -775,25 +771,17 @@ namespace System.Globalization // If not successful, throw if (retVal == null) + { throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported); + } // Return the one we found return retVal; } - //////////////////////////////////////////////////////////////////////// - // - // All the accessors - // - // Accessors for our data object items - // - //////////////////////////////////////////////////////////////////////// - - /////////// - // Identity // - /////////// - - // The real name used to construct the locale (ie: de-DE_phoneb) + /// + /// The real name used to construct the locale (ie: de-DE_phoneb) + /// internal string CultureName { get @@ -812,30 +800,18 @@ namespace System.Globalization } } - // Are overrides enabled? - internal bool UseUserOverride - { - get - { - return _bUseOverrides; - } - } + /// + /// Are overrides enabled? + /// + internal bool UseUserOverride => _bUseOverrides; - // locale name (ie: de-DE, NO sort information) - internal string SNAME - { - get - { - if (_sName == null) - { - _sName = string.Empty; - } - return _sName; - } - } + /// + /// locale name (ie: de-DE, NO sort information) + /// + internal string Name => _sName ?? string.Empty; // Parent name (which may be a custom locale/culture) - internal string SPARENT + internal string ParentName { get { @@ -849,21 +825,21 @@ namespace System.Globalization } // Localized pretty name for this locale (ie: Inglis (estados Unitos)) - internal string SLOCALIZEDDISPLAYNAME + internal string DisplayName { get { if (_sLocalizedDisplayName == null) { - if (this.IsSupplementalCustomCulture) + if (IsSupplementalCustomCulture) { - if (this.IsNeutralCulture) + if (IsNeutralCulture) { - _sLocalizedDisplayName = this.SNATIVELANGUAGE; + _sLocalizedDisplayName = NativeLanguageName; } else { - _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME; + _sLocalizedDisplayName = NativeName; } } else @@ -873,17 +849,17 @@ namespace System.Globalization const string ZH_CHT = "zh-CHT"; const string ZH_CHS = "zh-CHS"; - if (SNAME.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase)) + if (Name.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase)) { _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hant"); } - else if (SNAME.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase)) + else if (Name.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase)) { _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hans"); } else { - _sLocalizedDisplayName = GetLanguageDisplayName(SNAME); + _sLocalizedDisplayName = GetLanguageDisplayName(Name); } } catch (Exception) @@ -895,9 +871,9 @@ namespace System.Globalization if (string.IsNullOrEmpty(_sLocalizedDisplayName)) { // If its neutral use the language name - if (this.IsNeutralCulture) + if (IsNeutralCulture) { - _sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE; + _sLocalizedDisplayName = LocalizedLanguageName; } else { @@ -909,7 +885,7 @@ namespace System.Globalization ((ci = GetUserDefaultCulture()) != null) && !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) { - _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME; + _sLocalizedDisplayName = NativeName; } else { @@ -923,17 +899,19 @@ namespace System.Globalization } } - // English pretty name for this locale (ie: English (United States)) - internal string SENGDISPLAYNAME + /// + /// English pretty name for this locale (ie: English (United States)) + /// + internal string EnglishName { get { if (_sEnglishDisplayName == null) { // If its neutral use the language name - if (this.IsNeutralCulture) + if (IsNeutralCulture) { - _sEnglishDisplayName = this.SENGLISHLANGUAGE; + _sEnglishDisplayName = EnglishLanguageName; // differentiate the legacy display names switch (_sName) { @@ -953,19 +931,19 @@ namespace System.Globalization // Our existing names mostly look like: // "English" + "United States" -> "English (United States)" // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)" - if (this.SENGLISHLANGUAGE[this.SENGLISHLANGUAGE.Length - 1] == ')') + if (EnglishLanguageName[EnglishLanguageName.Length - 1] == ')') { // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)" _sEnglishDisplayName = string.Concat( - this.SENGLISHLANGUAGE.AsSpan(0, _sEnglishLanguage.Length - 1), + EnglishLanguageName.AsSpan(0, _sEnglishLanguage.Length - 1), ", ", - this.SENGCOUNTRY, + EnglishCountryName, ")"); } else { // "English" + "United States" -> "English (United States)" - _sEnglishDisplayName = this.SENGLISHLANGUAGE + " (" + this.SENGCOUNTRY + ")"; + _sEnglishDisplayName = EnglishLanguageName + " (" + EnglishCountryName + ")"; } } } @@ -974,17 +952,19 @@ namespace System.Globalization } } - // Native pretty name for this locale (ie: Deutsch (Deutschland)) - internal string SNATIVEDISPLAYNAME + /// + /// Native pretty name for this locale (ie: Deutsch (Deutschland)) + /// + internal string NativeName { get { if (_sNativeDisplayName == null) { // If its neutral use the language name - if (this.IsNeutralCulture) + if (IsNeutralCulture) { - _sNativeDisplayName = this.SNATIVELANGUAGE; + _sNativeDisplayName = NativeLanguageName; // differentiate the legacy display names switch (_sName) { @@ -1004,7 +984,7 @@ namespace System.Globalization if (string.IsNullOrEmpty(_sNativeDisplayName)) { // These should primarily be "Deutsch (Deutschland)" type names - _sNativeDisplayName = this.SNATIVELANGUAGE + " (" + this.SNATIVECOUNTRY + ")"; + _sNativeDisplayName = NativeLanguageName + " (" + NativeCountryName + ")"; } } } @@ -1012,23 +992,23 @@ namespace System.Globalization } } - // The culture name to be used in CultureInfo.CreateSpecificCulture() - internal string SSPECIFICCULTURE + /// + /// The culture name to be used in CultureInfo.CreateSpecificCulture() + /// + internal string SpecificCultureName { get { // This got populated during the culture initialization - Debug.Assert(_sSpecificCulture != null, "[CultureData.SSPECIFICCULTURE] Expected this.sSpecificCulture to be populated by culture data initialization already"); + Debug.Assert(_sSpecificCulture != null, "[CultureData.SpecificCultureName] Expected this.sSpecificCulture to be populated by culture data initialization already"); return _sSpecificCulture; } } - ///////////// - // Language // - ///////////// - - // iso 639 language name, ie: en - internal string SISO639LANGNAME + /// + /// iso 639 language name, ie: en + /// + internal string TwoLetterISOLanguageName { get { @@ -1040,8 +1020,10 @@ namespace System.Globalization } } - // iso 639 language name, ie: eng - internal string SISO639LANGNAME2 + /// + /// iso 639 language name, ie: eng + /// + internal string ThreeLetterISOLanguageName { get { @@ -1053,8 +1035,10 @@ namespace System.Globalization } } - // abbreviated windows language name (ie: enu) (non-standard, avoid this) - internal string SABBREVLANGNAME + /// + /// abbreviated windows language name (ie: enu) (non-standard, avoid this) + /// + internal string ThreeLetterWindowsLanguageName { get { @@ -1066,9 +1050,11 @@ namespace System.Globalization } } - // Localized name for this language (Windows Only) ie: Inglis - // This is only valid for Windows 8 and higher neutrals: - internal string SLOCALIZEDLANGUAGE + /// + /// Localized name for this language (Windows Only) ie: Inglis + /// This is only valid for Windows 8 and higher neutrals: + /// + private string LocalizedLanguageName { get { @@ -1082,7 +1068,7 @@ namespace System.Globalization ((ci = GetUserDefaultCulture()) != null) && !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) { - _sLocalizedLanguage = SNATIVELANGUAGE; + _sLocalizedLanguage = NativeLanguageName; } else { @@ -1094,8 +1080,10 @@ namespace System.Globalization } } - // English name for this language (Windows Only) ie: German - internal string SENGLISHLANGUAGE + /// + /// English name for this language (Windows Only) ie: German + /// + private string EnglishLanguageName { get { @@ -1107,8 +1095,10 @@ namespace System.Globalization } } - // Native name of this language (Windows Only) ie: Deutsch - internal string SNATIVELANGUAGE + /// + /// Native name of this language (Windows Only) ie: Deutsch + /// + private string NativeLanguageName { get { @@ -1120,12 +1110,10 @@ namespace System.Globalization } } - /////////// - // Region // - /////////// - - // region name (eg US) - internal string SREGIONNAME + /// + /// region name (eg US) + /// + internal string RegionName { get { @@ -1137,7 +1125,7 @@ namespace System.Globalization } } - internal int IGEOID + internal int GeoId { get { @@ -1149,8 +1137,10 @@ namespace System.Globalization } } - // localized name for the country - internal string SLOCALIZEDCOUNTRY + /// + /// localized name for the country + /// + internal string LocalizedCountryName { get { @@ -1158,7 +1148,7 @@ namespace System.Globalization { try { - _sLocalizedCountry = GetRegionDisplayName(SISO3166CTRYNAME); + _sLocalizedCountry = GetRegionDisplayName(TwoLetterISOCountryName); } catch (Exception) { @@ -1167,15 +1157,17 @@ namespace System.Globalization if (_sLocalizedCountry == null) { - _sLocalizedCountry = SNATIVECOUNTRY; + _sLocalizedCountry = NativeCountryName; } } return _sLocalizedCountry; } } - // english country name (RegionInfo) ie: Germany - internal string SENGCOUNTRY + /// + /// english country name (RegionInfo) ie: Germany + /// + internal string EnglishCountryName { get { @@ -1187,8 +1179,10 @@ namespace System.Globalization } } - // native country name (RegionInfo) ie: Deutschland - internal string SNATIVECOUNTRY + /// + /// native country name (RegionInfo) ie: Deutschland + /// + internal string NativeCountryName { get { @@ -1200,8 +1194,10 @@ namespace System.Globalization } } - // ISO 3166 Country Name - internal string SISO3166CTRYNAME + /// + /// ISO 3166 Country Name + /// + internal string TwoLetterISOCountryName { get { @@ -1213,8 +1209,10 @@ namespace System.Globalization } } - // 3 letter ISO 3166 country code - internal string SISO3166CTRYNAME2 + /// + /// 3 letter ISO 3166 country code + /// + internal string ThreeLetterISOCountryName { get { @@ -1226,7 +1224,7 @@ namespace System.Globalization } } - internal int IINPUTLANGUAGEHANDLE + internal int KeyboardLayoutId { get { @@ -1239,14 +1237,16 @@ namespace System.Globalization else { // Input Language is same as LCID for built-in cultures - _iInputLanguageHandle = this.ILANGUAGE; + _iInputLanguageHandle = LCID; } } return _iInputLanguageHandle; } } - // Console fallback name (ie: locale to use for console apps for unicode-only locales) + /// + /// Console fallback name (ie: locale to use for console apps for unicode-only locales) + /// internal string SCONSOLEFALLBACKNAME { get @@ -1259,8 +1259,10 @@ namespace System.Globalization } } - // (user can override) grouping of digits - internal int[] WAGROUPING + /// + /// (user can override) grouping of digits + /// + internal int[] NumberGroupSizes { get { @@ -1272,12 +1274,10 @@ namespace System.Globalization } } - - // internal string _sDecimalSeparator ; // (user can override) decimal separator - // internal string _sThousandSeparator ; // (user can override) thousands separator - - // Not a Number - internal string SNAN + /// + /// Not a Number + /// + private string NaNSymbol { get { @@ -1289,8 +1289,10 @@ namespace System.Globalization } } - // + Infinity - internal string SPOSINFINITY + /// + /// + Infinity + /// + private string PositiveInfinitySymbol { get { @@ -1302,8 +1304,10 @@ namespace System.Globalization } } - // - Infinity - internal string SNEGINFINITY + /// + /// - Infinity + /// + private string NegativeInfinitySymbol { get { @@ -1315,13 +1319,10 @@ namespace System.Globalization } } - - //////////// - // Percent // - /////////// - - // Negative Percent (0-3) - internal int INEGATIVEPERCENT + /// + /// Negative Percent (0-3) + /// + private int PercentNegativePattern { get { @@ -1334,8 +1335,10 @@ namespace System.Globalization } } - // Positive Percent (0-11) - internal int IPOSITIVEPERCENT + /// + /// Positive Percent (0-11) + /// + private int PercentPositivePattern { get { @@ -1348,8 +1351,10 @@ namespace System.Globalization } } - // Percent (%) symbol - internal string SPERCENT + /// + /// Percent (%) symbol + /// + private string PercentSymbol { get { @@ -1361,8 +1366,10 @@ namespace System.Globalization } } - // PerMille symbol - internal string SPERMILLE + /// + /// PerMille symbol + /// + private string PerMilleSymbol { get { @@ -1374,12 +1381,10 @@ namespace System.Globalization } } - ///////////// - // Currency // - ///////////// - - // (user can override) local monetary symbol, eg: $ - internal string SCURRENCY + /// + /// (user can override) local monetary symbol, eg: $ + /// + internal string CurrencySymbol { get { @@ -1391,8 +1396,10 @@ namespace System.Globalization } } - // international monetary symbol (RegionInfo), eg: USD - internal string SINTLSYMBOL + /// + /// international monetary symbol (RegionInfo), eg: USD + /// + internal string ISOCurrencySymbol { get { @@ -1404,8 +1411,10 @@ namespace System.Globalization } } - // English name for this currency (RegionInfo), eg: US Dollar - internal string SENGLISHCURRENCY + /// + /// English name for this currency (RegionInfo), eg: US Dollar + /// + internal string CurrencyEnglishName { get { @@ -1417,8 +1426,10 @@ namespace System.Globalization } } - // Native name for this currency (RegionInfo), eg: Schweiz Frank - internal string SNATIVECURRENCY + /// + /// Native name for this currency (RegionInfo), eg: Schweiz Frank + /// + internal string CurrencyNativeName { get { @@ -1430,12 +1441,11 @@ namespace System.Globalization } } - // internal int iCurrencyDigits ; // (user can override) # local monetary fractional digits - // internal int iCurrency ; // (user can override) positive currency format - // internal int iNegativeCurrency ; // (user can override) negative currency format - // (user can override) monetary grouping of digits - internal int[] WAMONGROUPING + /// + /// (user can override) monetary grouping of digits + /// + internal int[] CurrencyGroupSizes { get { @@ -1447,8 +1457,10 @@ namespace System.Globalization } } - // (user can override) system of measurement 0=metric, 1=US (RegionInfo) - internal int IMEASURE + /// + /// (user can override) system of measurement 0=metric, 1=US (RegionInfo) + /// + internal int MeasurementSystem { get { @@ -1460,8 +1472,10 @@ namespace System.Globalization } } - // (user can override) list Separator - internal string SLIST + /// + /// (user can override) list Separator + /// + internal string ListSeparator { get { @@ -1473,13 +1487,10 @@ namespace System.Globalization } } - - //////////////////////////// - // Calendar/Time (Gregorian) // - //////////////////////////// - - // (user can override) AM designator - internal string SAM1159 + /// + /// (user can override) AM designator + /// + internal string AMDesignator { get { @@ -1491,8 +1502,10 @@ namespace System.Globalization } } - // (user can override) PM designator - internal string SPM2359 + /// + /// (user can override) PM designator + /// + internal string PMDesignator { get { @@ -1504,7 +1517,9 @@ namespace System.Globalization } } - // (user can override) time format + /// + /// (user can override) time format + /// internal string[] LongTimes { get @@ -1527,9 +1542,10 @@ namespace System.Globalization } } - // short time format - // Short times (derived from long times format) - // TODO: NLS Arrowhead - On Windows 7 we should have short times so this isn't necessary + /// + /// short time format + /// Short times (derived from long times format) + /// internal string[] ShortTimes { get @@ -1661,14 +1677,14 @@ namespace System.Globalization private static int GetIndexOfNextTokenAfterSeconds(string time, int index, out bool containsSpace) { - bool bEscape = false; + bool shouldEscape = false; containsSpace = false; for (; index < time.Length; index++) { switch (time[index]) { case '\'': - bEscape = !bEscape; + shouldEscape = !shouldEscape; continue; case '\\': index++; @@ -1684,7 +1700,7 @@ namespace System.Globalization case 'm': case 'H': case 'h': - if (bEscape) + if (shouldEscape) { continue; } @@ -1696,7 +1712,7 @@ namespace System.Globalization } // (user can override) first day of week - internal int IFIRSTDAYOFWEEK + internal int FirstDayOfWeek { get { @@ -1709,7 +1725,7 @@ namespace System.Globalization } // (user can override) first week of year - internal int IFIRSTWEEKOFYEAR + internal int CalendarWeekRule { get { @@ -1721,88 +1737,82 @@ namespace System.Globalization } } - // (user can override default only) short date format + /// + /// (user can override default only) short date format + /// internal string[] ShortDates(CalendarId calendarId) { return GetCalendar(calendarId).saShortDates; } - // (user can override default only) long date format + /// + /// (user can override default only) long date format + /// internal string[] LongDates(CalendarId calendarId) { return GetCalendar(calendarId).saLongDates; } - // (user can override) date year/month format. + /// + /// (user can override) date year/month format. + /// internal string[] YearMonths(CalendarId calendarId) { return GetCalendar(calendarId).saYearMonths; } - // day names internal string[] DayNames(CalendarId calendarId) { return GetCalendar(calendarId).saDayNames; } - // abbreviated day names internal string[] AbbreviatedDayNames(CalendarId calendarId) { - // Get abbreviated day names for this calendar from the OS if necessary return GetCalendar(calendarId).saAbbrevDayNames; } - // The super short day names internal string[] SuperShortDayNames(CalendarId calendarId) { return GetCalendar(calendarId).saSuperShortDayNames; } - // month names internal string[] MonthNames(CalendarId calendarId) { return GetCalendar(calendarId).saMonthNames; } - // Genitive month names internal string[] GenitiveMonthNames(CalendarId calendarId) { return GetCalendar(calendarId).saMonthGenitiveNames; } - // month names internal string[] AbbreviatedMonthNames(CalendarId calendarId) { return GetCalendar(calendarId).saAbbrevMonthNames; } - // Genitive month names internal string[] AbbreviatedGenitiveMonthNames(CalendarId calendarId) { return GetCalendar(calendarId).saAbbrevMonthGenitiveNames; } - // Leap year month names - // Note: This only applies to Hebrew, and it basically adds a "1" to the 6th month name - // the non-leap names skip the 7th name in the normal month name array + /// > + /// Note: This only applies to Hebrew, and it basically adds a "1" to the 6th month name + /// the non-leap names skip the 7th name in the normal month name array + /// internal string[] LeapYearMonthNames(CalendarId calendarId) { return GetCalendar(calendarId).saLeapYearMonthNames; } - // month/day format (single string, no override) internal string MonthDay(CalendarId calendarId) { return GetCalendar(calendarId).sMonthDay; } - - - ///////////// - // Calendars // - ///////////// - - // all available calendar type(s), The first one is the default calendar. + /// + /// All available calendar type(s). The first one is the default calendar. + /// internal CalendarId[] CalendarIds { get @@ -1876,10 +1886,12 @@ namespace System.Globalization } } - // Native calendar names. index of optional calendar - 1, empty if no optional calendar at that number + /// + /// Native calendar names. Index of optional calendar - 1, empty if + /// no optional calendar at that number + /// internal string CalendarName(CalendarId calendarId) { - // Get the calendar return GetCalendar(calendarId).sNativeName; } @@ -1905,18 +1917,13 @@ namespace System.Globalization if (calendarData == null) { Debug.Assert(_sWindowsName != null, "[CultureData.GetCalendar] Expected _sWindowsName to be populated by already"); - calendarData = new CalendarData(_sWindowsName, calendarId, this.UseUserOverride); + calendarData = new CalendarData(_sWindowsName, calendarId, UseUserOverride); _calendars[calendarIndex] = calendarData; } return calendarData; } - /////////////////// - // Text Information // - /////////////////// - - // IsRightToLeft internal bool IsRightToLeft { get @@ -1926,19 +1933,18 @@ namespace System.Globalization // 1 - Right to left (eg arabic locales) // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales) // 3 - Vertical top to bottom with columns proceeding to the right - return (this.IREADINGLAYOUT == 1); + return ReadingLayout == 1; } } - // IREADINGLAYOUT - // Returns one of the following 4 reading layout values: - // 0 - Left to right (eg en-US) - // 1 - Right to left (eg arabic locales) - // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales) - // 3 - Vertical top to bottom with columns proceeding to the right - // - // If exposed as a public API, we'd have an enum with those 4 values - private int IREADINGLAYOUT + /// + /// Returns one of the following 4 reading layout values: + /// 0 - Left to right (eg en-US) + /// 1 - Right to left (eg arabic locales) + /// 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales) + /// 3 - Vertical top to bottom with columns proceeding to the right + /// + private int ReadingLayout { get { @@ -1952,43 +1958,45 @@ namespace System.Globalization } } - // The TextInfo name never includes that alternate sort and is always specific - // For customs, it uses the SortLocale (since the textinfo is not exposed in Win7) - // en -> en-US - // en-US -> en-US - // fj (custom neutral) -> en-US (assuming that en-US is the sort locale for fj) - // fj_FJ (custom specific) -> en-US (assuming that en-US is the sort locale for fj-FJ) - // es-ES_tradnl -> es-ES - internal string STEXTINFO // Text info name to use for text information + /// + /// // Text info name to use for text information + /// The TextInfo name never includes that alternate sort and is always specific + /// For customs, it uses the SortLocale (since the textinfo is not exposed in Win7) + /// en -> en-US + /// en-US -> en-US + /// fj (custom neutral) -> en-US (assuming that en-US is the sort locale for fj) + /// fj_FJ (custom specific) -> en-US (assuming that en-US is the sort locale for fj-FJ) + /// es-ES_tradnl -> es-ES + /// + internal string TextInfoName { get { // Note: Custom cultures might point at another culture's textinfo, however windows knows how // to redirect it to the desired textinfo culture, so this is OK. - Debug.Assert(_sRealName != null, "[CultureData.STEXTINFO] Expected _sRealName to be populated by already"); - return (_sRealName); + Debug.Assert(_sRealName != null, "[CultureData.TextInfoName] Expected _sRealName to be populated by already"); + return _sRealName; } } - // Compare info name (including sorting key) to use if custom - internal string SCOMPAREINFO + /// + /// Compare info name (including sorting key) to use if custom + /// + internal string SortName { get { - Debug.Assert(_sRealName != null, "[CultureData.SCOMPAREINFO] Expected _sRealName to be populated by already"); - return (_sRealName); + Debug.Assert(_sRealName != null, "[CultureData.SortName] Expected _sRealName to be populated by already"); + return _sRealName; } } - internal bool IsSupplementalCustomCulture - { - get - { - return IsCustomCultureId(this.ILANGUAGE); - } - } + internal bool IsSupplementalCustomCulture => IsCustomCultureId(LCID); - internal int IDEFAULTANSICODEPAGE // default ansi code page ID (ACP) + /// + /// Default ansi code page ID (ACP) + /// + internal int ANSICodePage { get { @@ -2000,7 +2008,10 @@ namespace System.Globalization } } - internal int IDEFAULTOEMCODEPAGE // default oem code page ID (OCP or OEM) + /// + /// Default oem code page ID (OCP or OEM). + /// + internal int OEMCodePage { get { @@ -2012,7 +2023,10 @@ namespace System.Globalization } } - internal int IDEFAULTMACCODEPAGE // default macintosh code page + /// + /// Default macintosh code page. + /// + internal int MacCodePage { get { @@ -2024,7 +2038,10 @@ namespace System.Globalization } } - internal int IDEFAULTEBCDICCODEPAGE // default EBCDIC code page + /// + /// Default EBCDIC code page. + /// + internal int EBCDICCodePage { get { @@ -2036,13 +2053,13 @@ namespace System.Globalization } } - internal int ILANGUAGE + internal int LCID { get { if (_iLanguage == 0) { - Debug.Assert(_sRealName != null, "[CultureData.ILANGUAGE] Expected this.sRealName to be populated already"); + Debug.Assert(_sRealName != null, "[CultureData.LCID] Expected this.sRealName to be populated already"); _iLanguage = LocaleNameToLCID(_sRealName); } return _iLanguage; @@ -2062,11 +2079,13 @@ namespace System.Globalization { get { - return string.IsNullOrEmpty(this.SNAME); + return string.IsNullOrEmpty(Name); } } - // Get an instance of our default calendar + /// + /// Get an instance of our default calendar + /// internal Calendar DefaultCalendar { get @@ -2080,40 +2099,37 @@ namespace System.Globalization if (defaultCalId == 0) { - defaultCalId = this.CalendarIds[0]; + defaultCalId = CalendarIds[0]; } return CultureInfo.GetCalendarInstance(defaultCalId); } } - // All of our era names + /// + /// All of our era names + /// internal string[] EraNames(CalendarId calendarId) { Debug.Assert(calendarId > 0, "[CultureData.saEraNames] Expected Calendar.ID > 0"); - - return this.GetCalendar(calendarId).saEraNames; + return GetCalendar(calendarId).saEraNames; } internal string[] AbbrevEraNames(CalendarId calendarId) { Debug.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0"); - - return this.GetCalendar(calendarId).saAbbrevEraNames; + return GetCalendar(calendarId).saAbbrevEraNames; } internal string[] AbbreviatedEnglishEraNames(CalendarId calendarId) { Debug.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0"); - - return this.GetCalendar(calendarId).saAbbrevEnglishEraNames; + return GetCalendar(calendarId).saAbbrevEnglishEraNames; } - //// string array DEFAULTS - //// Note: GetDTFIOverrideValues does the user overrides for these, so we don't have to. - - - // Time separator (derived from time format) + /// + /// Time separator (derived from time format) + /// internal string TimeSeparator { get @@ -2133,7 +2149,9 @@ namespace System.Globalization } } - // Date separator (derived from short date format) + /// + /// Date separator (derived from short date format) + /// internal string DateSeparator(CalendarId calendarId) { if (calendarId == CalendarId.JAPAN && !LocalAppContextSwitches.EnforceLegacyJapaneseDateParsing) @@ -2150,29 +2168,23 @@ namespace System.Globalization return GetDateSeparator(ShortDates(calendarId)[0]); } - ////////////////////////////////////// - // Helper Functions to get derived properties // - ////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////////// - // - // Unescape a NLS style quote string - // - // This removes single quotes: - // 'fred' -> fred - // 'fred -> fred - // fred' -> fred - // fred's -> freds - // - // This removes the first \ of escaped characters: - // fred\'s -> fred's - // a\\b -> a\b - // a\b -> ab - // - // We don't build the stringbuilder unless we find a ' or a \. If we find a ' or a \, we - // always build a stringbuilder because we need to remove the ' or \. - // - //////////////////////////////////////////////////////////////////////////// + /// + /// Unescape a NLS style quote string + /// + /// This removes single quotes: + /// 'fred' -> fred + /// 'fred -> fred + /// fred' -> fred + /// fred's -> freds + /// + /// This removes the first \ of escaped characters: + /// fred\'s -> fred's + /// a\\b -> a\b + /// a\b -> ab + /// + /// We don't build the stringbuilder unless we find a ' or a \. If we find a ' or a \, we + /// always build a stringbuilder because we need to remove the ' or \. + /// private static string UnescapeNlsString(string str, int start, int end) { Debug.Assert(str != null); @@ -2211,34 +2223,30 @@ namespace System.Globalization } if (result == null) - return (str.Substring(start, end - start + 1)); + { + return str.Substring(start, end - start + 1); + } - return (result.ToString()); + return result.ToString(); } + /// + /// Time format separator (ie: : in 12:39:00) + /// We calculate this from the provided time format + /// private static string GetTimeSeparator(string format) { - // Time format separator (ie: : in 12:39:00) - // - // We calculate this from the provided time format - // - - // - // Find the time separator so that we can pretend we know STIME. - // + // Find the time separator so that we can pretend we know TimeSeparator. return GetSeparator(format, "Hhms"); } + /// + /// Date format separator (ie: / in 9/1/03) + /// We calculate this from the provided short date + /// private static string GetDateSeparator(string format) { - // Date format separator (ie: / in 9/1/03) - // - // We calculate this from the provided short date - // - - // - // Find the date separator so that we can pretend we know SDATE. - // + // Find the date separator so that we can pretend we know DateSeparator. return GetSeparator(format, "dyM"); } @@ -2313,104 +2321,100 @@ namespace System.Globalization internal static bool IsCustomCultureId(int cultureId) { - return (cultureId == CultureInfo.LOCALE_CUSTOM_DEFAULT || cultureId == CultureInfo.LOCALE_CUSTOM_UNSPECIFIED); + return cultureId == CultureInfo.LOCALE_CUSTOM_DEFAULT || cultureId == CultureInfo.LOCALE_CUSTOM_UNSPECIFIED; } internal void GetNFIValues(NumberFormatInfo nfi) { - if (GlobalizationMode.Invariant || this.IsInvariantCulture) + if (GlobalizationMode.Invariant || IsInvariantCulture) { - // FUTURE: NumberFormatInfo already has default values for many of these fields. Can we not do this? - nfi.positiveSign = _sPositiveSign; - nfi.negativeSign = _sNegativeSign; + nfi._positiveSign = _sPositiveSign; + nfi._negativeSign = _sNegativeSign; - nfi.numberGroupSeparator = _sThousandSeparator; - nfi.numberDecimalSeparator = _sDecimalSeparator; - nfi.numberDecimalDigits = _iDigits; - nfi.numberNegativePattern = _iNegativeNumber; + nfi._numberGroupSeparator = _sThousandSeparator; + nfi._numberDecimalSeparator = _sDecimalSeparator; + nfi._numberDecimalDigits = _iDigits; + nfi._numberNegativePattern = _iNegativeNumber; - nfi.currencySymbol = _sCurrency; - nfi.currencyGroupSeparator = _sMonetaryThousand; - nfi.currencyDecimalSeparator = _sMonetaryDecimal; - nfi.currencyDecimalDigits = _iCurrencyDigits; - nfi.currencyNegativePattern = _iNegativeCurrency; - nfi.currencyPositivePattern = _iCurrency; + nfi._currencySymbol = _sCurrency; + nfi._currencyGroupSeparator = _sMonetaryThousand; + nfi._currencyDecimalSeparator = _sMonetaryDecimal; + nfi._currencyDecimalDigits = _iCurrencyDigits; + nfi._currencyNegativePattern = _iNegativeCurrency; + nfi._currencyPositivePattern = _iCurrency; } else { Debug.Assert(_sWindowsName != null, "[CultureData.GetNFIValues] Expected _sWindowsName to be populated by already"); // String values - nfi.positiveSign = GetLocaleInfo(LocaleStringData.PositiveSign); - nfi.negativeSign = GetLocaleInfo(LocaleStringData.NegativeSign); + nfi._positiveSign = GetLocaleInfo(LocaleStringData.PositiveSign); + nfi._negativeSign = GetLocaleInfo(LocaleStringData.NegativeSign); - nfi.numberDecimalSeparator = GetLocaleInfo(LocaleStringData.DecimalSeparator); - nfi.numberGroupSeparator = GetLocaleInfo(LocaleStringData.ThousandSeparator); - nfi.currencyGroupSeparator = GetLocaleInfo(LocaleStringData.MonetaryThousandSeparator); - nfi.currencyDecimalSeparator = GetLocaleInfo(LocaleStringData.MonetaryDecimalSeparator); - nfi.currencySymbol = GetLocaleInfo(LocaleStringData.MonetarySymbol); + nfi._numberDecimalSeparator = GetLocaleInfo(LocaleStringData.DecimalSeparator); + nfi._numberGroupSeparator = GetLocaleInfo(LocaleStringData.ThousandSeparator); + nfi._currencyGroupSeparator = GetLocaleInfo(LocaleStringData.MonetaryThousandSeparator); + nfi._currencyDecimalSeparator = GetLocaleInfo(LocaleStringData.MonetaryDecimalSeparator); + nfi._currencySymbol = GetLocaleInfo(LocaleStringData.MonetarySymbol); // Numeric values - nfi.numberDecimalDigits = GetLocaleInfo(LocaleNumberData.FractionalDigitsCount); - nfi.currencyDecimalDigits = GetLocaleInfo(LocaleNumberData.MonetaryFractionalDigitsCount); - nfi.currencyPositivePattern = GetLocaleInfo(LocaleNumberData.PositiveMonetaryNumberFormat); - nfi.currencyNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeMonetaryNumberFormat); - nfi.numberNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeNumberFormat); + nfi._numberDecimalDigits = GetLocaleInfo(LocaleNumberData.FractionalDigitsCount); + nfi._currencyDecimalDigits = GetLocaleInfo(LocaleNumberData.MonetaryFractionalDigitsCount); + nfi._currencyPositivePattern = GetLocaleInfo(LocaleNumberData.PositiveMonetaryNumberFormat); + nfi._currencyNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeMonetaryNumberFormat); + nfi._numberNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeNumberFormat); // LOCALE_SNATIVEDIGITS (array of 10 single character strings). string digits = GetLocaleInfo(LocaleStringData.Digits); - nfi.nativeDigits = new string[10]; - for (int i = 0; i < nfi.nativeDigits.Length; i++) + nfi._nativeDigits = new string[10]; + for (int i = 0; i < nfi._nativeDigits.Length; i++) { - nfi.nativeDigits[i] = char.ToString(digits[i]); + nfi._nativeDigits[i] = char.ToString(digits[i]); } - nfi.digitSubstitution = GetDigitSubstitution(_sRealName); + nfi._digitSubstitution = GetDigitSubstitution(_sRealName); } - // // Gather additional data - // - nfi.numberGroupSizes = this.WAGROUPING; - nfi.currencyGroupSizes = this.WAMONGROUPING; + nfi._numberGroupSizes = NumberGroupSizes; + nfi._currencyGroupSizes = CurrencyGroupSizes; // prefer the cached value since these do not have user overrides - nfi.percentNegativePattern = this.INEGATIVEPERCENT; - nfi.percentPositivePattern = this.IPOSITIVEPERCENT; - nfi.percentSymbol = this.SPERCENT; - nfi.perMilleSymbol = this.SPERMILLE; + nfi._percentNegativePattern = PercentNegativePattern; + nfi._percentPositivePattern = PercentPositivePattern; + nfi._percentSymbol = PercentSymbol; + nfi._perMilleSymbol = PerMilleSymbol; - nfi.negativeInfinitySymbol = this.SNEGINFINITY; - nfi.positiveInfinitySymbol = this.SPOSINFINITY; - nfi.nanSymbol = this.SNAN; + nfi._negativeInfinitySymbol = NegativeInfinitySymbol; + nfi._positiveInfinitySymbol = PositiveInfinitySymbol; + nfi._nanSymbol = NaNSymbol; - // // We don't have percent values, so use the number values - // - nfi.percentDecimalDigits = nfi.numberDecimalDigits; - nfi.percentDecimalSeparator = nfi.numberDecimalSeparator; - nfi.percentGroupSizes = nfi.numberGroupSizes; - nfi.percentGroupSeparator = nfi.numberGroupSeparator; + nfi._percentDecimalDigits = nfi._numberDecimalDigits; + nfi._percentDecimalSeparator = nfi._numberDecimalSeparator; + nfi._percentGroupSizes = nfi._numberGroupSizes; + nfi._percentGroupSeparator = nfi._numberGroupSeparator; - // // Clean up a few odd values - // // Windows usually returns an empty positive sign, but we like it to be "+" - if (nfi.positiveSign == null || nfi.positiveSign.Length == 0) nfi.positiveSign = "+"; + if (nfi._positiveSign == null || nfi._positiveSign.Length == 0) + { + nfi._positiveSign = "+"; + } - //Special case for Italian. The currency decimal separator in the control panel is the empty string. When the user - //specifies C4 as the currency format, this results in the number apparently getting multiplied by 10000 because the - //decimal point doesn't show up. We'll just hack this here because our default currency format will never use nfi. - if (nfi.currencyDecimalSeparator == null || nfi.currencyDecimalSeparator.Length == 0) + // Special case for Italian. The currency decimal separator in the control panel is the empty string. When the user + // specifies C4 as the currency format, this results in the number apparently getting multiplied by 10000 because the + // decimal point doesn't show up. We'll just hack this here because our default currency format will never use nfi. + if (nfi._currencyDecimalSeparator == null || nfi._currencyDecimalSeparator.Length == 0) { - nfi.currencyDecimalSeparator = nfi.numberDecimalSeparator; + nfi._currencyDecimalSeparator = nfi._numberDecimalSeparator; } } - // Helper - // This is ONLY used for caching names and shouldn't be used for anything else - internal static string AnsiToLower(string testString) => - TextInfo.ToLowerAsciiInvariant(testString); + /// + /// This is ONLY used for caching names and shouldn't be used for anything else + /// + internal static string AnsiToLower(string testString) => TextInfo.ToLowerAsciiInvariant(testString); /// /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs index f662788..c5479de 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs @@ -24,14 +24,10 @@ namespace System.Globalization if (GlobalizationMode.Invariant) return CultureInfo.InvariantCulture; - const uint LOCALE_SNAME = 0x0000005c; - const string LOCALE_NAME_USER_DEFAULT = null; - const string LOCALE_NAME_SYSTEM_DEFAULT = "!x-sys-default-locale"; - - string strDefault = CultureData.GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME); + string strDefault = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_USER_DEFAULT, Interop.Kernel32.LOCALE_SNAME); if (strDefault == null) { - strDefault = CultureData.GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_SNAME); + strDefault = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_SYSTEM_DEFAULT, Interop.Kernel32.LOCALE_SNAME); if (strDefault == null) { diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs index 1535126..01e5756 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs @@ -35,12 +35,25 @@ using Internal.Runtime.Augments; namespace System.Globalization { + /// + /// This class represents the software preferences of a particular culture + /// or community. It includes information such as the language, writing + /// system and a calendar used by the culture as well as methods for + /// common operations such as printing dates and sorting strings. + /// + /// + /// !!!! NOTE WHEN CHANGING THIS CLASS !!!! + /// If adding or removing members to this class, please update + /// CultureInfoBaseObject in ndp/clr/src/vm/object.h. Note, the "actual" + /// layout of the class may be different than the order in which members + /// are declared. For instance, all reference types will come first in the + /// class before value types (like ints, bools, etc) regardless of the + /// order in which they are declared. The best way to see the actual + /// order of the class is to do a !dumpobj on an instance of the managed + /// object inside of the debugger. + /// public partial class CultureInfo : IFormatProvider, ICloneable { - //--------------------------------------------------------------------// - // Internal Information // - //--------------------------------------------------------------------// - // We use an RFC4646 type string to construct CultureInfo. // This string is stored in _name and is authoritative. // We use the _cultureData to get the data for our object @@ -68,9 +81,9 @@ namespace System.Globalization // en-US en-US en-US en-US // de-de_phoneb de-DE_phoneb de-DE de-DE_phoneb // fj-fj (custom) fj-FJ fj-FJ en-US (if specified sort is en-US) - // en en + // en en // - // Note that in Silverlight we ask the OS for the text and sort behavior, so the + // Note that in Silverlight we ask the OS for the text and sort behavior, so the // textinfo and compareinfo names are the same as the name // This has a de-DE, de-DE_phoneb or fj-FJ style name @@ -85,30 +98,21 @@ namespace System.Globalization // Otherwise its the sort name, ie: de-DE or de-DE_phoneb private string _sortName; - //--------------------------------------------------------------------// - // - // Static data members - // - //--------------------------------------------------------------------// - - //Get the current user default culture. This one is almost always used, so we create it by default. + // Get the current user default culture. This one is almost always used, so we create it by default. private static volatile CultureInfo s_userDefaultCulture; //The culture used in the user interface. This is mostly used to load correct localized resources. private static volatile CultureInfo s_userDefaultUICulture; - // - // All of the following will be created on demand. - // // WARNING: We allow diagnostic tools to directly inspect these three members (s_InvariantCultureInfo, s_DefaultThreadCurrentUICulture and s_DefaultThreadCurrentCulture) - // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details. - // Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools. + // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details. + // Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools. // Get in touch with the diagnostics team if you have questions. - //The Invariant culture; + // The Invariant culture; private static readonly CultureInfo s_InvariantCultureInfo = new CultureInfo(CultureData.Invariant, isReadOnly: true); - //These are defaults that we use if a thread has not opted into having an explicit culture + // These are defaults that we use if a thread has not opted into having an explicit culture private static volatile CultureInfo s_DefaultThreadCurrentUICulture; private static volatile CultureInfo s_DefaultThreadCurrentCulture; @@ -132,9 +136,9 @@ namespace System.Globalization private static readonly object _lock = new object(); private static volatile Dictionary s_NameCachedCultures; - private static volatile Dictionary s_LcidCachedCultures; + private static volatile Dictionary s_LcidCachedCultures; - //The parent culture. + // The parent culture. private CultureInfo _parent; // LOCALE constants of interest to us internally and privately for LCID functions @@ -158,14 +162,7 @@ namespace System.Globalization return s_userDefaultUICulture; } - //////////////////////////////////////////////////////////////////////// - // - // CultureInfo Constructors - // - //////////////////////////////////////////////////////////////////////// - - public CultureInfo(string name) - : this(name, true) + public CultureInfo(string name) : this(name, true) { } @@ -173,8 +170,7 @@ namespace System.Globalization { if (name == null) { - throw new ArgumentNullException(nameof(name), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(name)); } // Get our data providing record @@ -186,7 +182,7 @@ namespace System.Globalization } _name = _cultureData.CultureName; - _isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo)); + _isInherited = GetType() != typeof(CultureInfo); } private CultureInfo(CultureData cultureData, bool isReadOnly = false) @@ -232,22 +228,23 @@ namespace System.Globalization // Can't support unknown custom cultures and we do not support neutral or // non-custom user locales. throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported); - default: // Now see if this LCID is supported in the system default CultureData table. _cultureData = CultureData.GetCultureData(culture, useUserOverride); break; } - _isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo)); + _isInherited = GetType() != typeof(CultureInfo); _name = _cultureData.CultureName; } - // Constructor called by SQL Server's special munged culture - creates a culture with - // a TextInfo and CompareInfo that come from a supplied alternate source. This object - // is ALWAYS read-only. - // Note that we really cannot use an LCID version of this override as the cached - // name we create for it has to include both names, and the logic for this is in - // the GetCultureInfo override *only*. + /// + /// Constructor called by SQL Server's special munged culture - creates a culture with + /// a TextInfo and CompareInfo that come from a supplied alternate source. This object + /// is ALWAYS read-only. + /// Note that we really cannot use an LCID version of this override as the cached + /// name we create for it has to include both names, and the logic for this is in + /// the GetCultureInfo override *only*. + /// internal CultureInfo(string cultureName, string textAndCompareCultureName) { if (cultureName == null) @@ -257,7 +254,9 @@ namespace System.Globalization _cultureData = CultureData.GetCultureData(cultureName, false); if (_cultureData == null) + { throw new CultureNotFoundException(nameof(cultureName), cultureName, SR.Argument_CultureNotSupported); + } _name = _cultureData.CultureName; @@ -266,38 +265,34 @@ namespace System.Globalization _textInfo = altCulture.TextInfo; } - // We do this to try to return the system UI language and the default user languages - // This method will fallback if this fails (like Invariant) - // + /// + /// We do this to try to return the system UI language and the default user languages + /// This method will fallback if this fails (like Invariant) + /// private static CultureInfo GetCultureByName(string name) { - CultureInfo ci = null; - // Try to get our culture try { - ci = new CultureInfo(name); - ci._isReadOnly = true; + return new CultureInfo(name) + { + _isReadOnly = true + }; } catch (ArgumentException) { + return InvariantCulture; } - - if (ci == null) - { - ci = InvariantCulture; - } - - return ci; } - // - // Return a specific culture. A tad irrelevent now since we always return valid data - // for neutral locales. - // - // Note that there's interesting behavior that tries to find a smaller name, ala RFC4647, - // if we can't find a bigger name. That doesn't help with things like "zh" though, so - // the approach is of questionable value - // + /// + /// Return a specific culture. A tad irrelevent now since we always + /// return valid data for neutral locales. + /// + /// Note that there's interesting behavior that tries to find a + /// smaller name, ala RFC4647, if we can't find a bigger name. + /// That doesn't help with things like "zh" though, so the approach + /// is of questionable value + /// public static CultureInfo CreateSpecificCulture(string name) { CultureInfo culture; @@ -311,11 +306,8 @@ namespace System.Globalization // When CultureInfo throws this exception, it may be because someone passed the form // like "az-az" because it came out of an http accept lang. We should try a little // parsing to perhaps fall back to "az" here and use *it* to create the neutral. - - int idx; - culture = null; - for (idx = 0; idx < name.Length; idx++) + for (int idx = 0; idx < name.Length; idx++) { if ('-' == name[idx]) { @@ -345,7 +337,7 @@ namespace System.Globalization return culture; } - return new CultureInfo(culture._cultureData.SSPECIFICCULTURE); + return new CultureInfo(culture._cultureData.SpecificCultureName); } internal static bool VerifyCultureName(string cultureName, bool throwException) @@ -353,7 +345,6 @@ namespace System.Globalization // This function is used by ResourceManager.GetResourceFileName(). // ResourceManager searches for resource using CultureInfo.Name, // so we should check against CultureInfo.Name. - for (int i = 0; i < cultureName.Length; i++) { char c = cultureName[i]; @@ -373,8 +364,8 @@ namespace System.Globalization internal static bool VerifyCultureName(CultureInfo culture, bool throwException) { - //If we have an instance of one of our CultureInfos, the user can't have changed the - //name and we know that all names are valid in files. + // If we have an instance of one of our CultureInfos, the user can't have changed the + // name and we know that all names are valid in files. if (!culture._isInherited) { return true; @@ -383,26 +374,21 @@ namespace System.Globalization return VerifyCultureName(culture.Name, throwException); } - //////////////////////////////////////////////////////////////////////// - // - // CurrentCulture - // - // This instance provides methods based on the current user settings. - // These settings are volatile and may change over the lifetime of the - // thread. - // - //////////////////////////////////////////////////////////////////////// - - // - // We use the following order to return CurrentCulture and CurrentUICulture - // o Use WinRT to return the current user profile language - // o use current thread culture if the user already set one using CurrentCulture/CurrentUICulture - // o use thread culture if the user already set one using DefaultThreadCurrentCulture - // or DefaultThreadCurrentUICulture - // o Use NLS default user culture - // o Use NLS default system culture - // o Use Invariant culture - // + /// + /// This instance provides methods based on the current user settings. + /// These settings are volatile and may change over the lifetime of the + /// thread. + /// + /// + /// We use the following order to return CurrentCulture and CurrentUICulture + /// o Use WinRT to return the current user profile language + /// o use current thread culture if the user already set one using CurrentCulture/CurrentUICulture + /// o use thread culture if the user already set one using DefaultThreadCurrentCulture + /// or DefaultThreadCurrentUICulture + /// o Use NLS default user culture + /// o Use NLS default system culture + /// o Use Invariant culture + /// public static CultureInfo CurrentCulture { get @@ -436,7 +422,6 @@ namespace System.Globalization return s_userDefaultCulture ?? InitializeUserDefaultCulture(); } - set { if (value == null) @@ -504,7 +489,6 @@ namespace System.Globalization return UserDefaultUICulture; } - set { if (value == null) @@ -549,23 +533,22 @@ namespace System.Globalization public static CultureInfo DefaultThreadCurrentCulture { - get { return s_DefaultThreadCurrentCulture; } + get => s_DefaultThreadCurrentCulture; set { // If you add pre-conditions to this method, check to see if you also need to // add them to Thread.CurrentCulture.set. - s_DefaultThreadCurrentCulture = value; } } public static CultureInfo DefaultThreadCurrentUICulture { - get { return s_DefaultThreadCurrentUICulture; } + get => s_DefaultThreadCurrentUICulture; set { - //If they're trying to use a Culture with a name that we can't use in resource lookup, - //don't even let them set it on the thread. + // If they're trying to use a Culture with a name that we can't use in resource lookup, + // don't even let them set it on the thread. // If you add more pre-conditions to this method, check to see if you also need to // add them to Thread.CurrentUICulture.set. @@ -579,20 +562,14 @@ namespace System.Globalization } } - //////////////////////////////////////////////////////////////////////// - // - // InvariantCulture - // - // This instance provides methods, for example for casing and sorting, - // that are independent of the system and current user settings. It - // should be used only by processes such as some system services that - // require such invariant results (eg. file systems). In general, - // the results are not linguistically correct and do not match any - // culture info. - // - //////////////////////////////////////////////////////////////////////// - - + /// + /// This instance provides methods, for example for casing and sorting, + /// that are independent of the system and current user settings. It + /// should be used only by processes such as some system services that + /// require such invariant results (eg. file systems). In general, + /// the results are not linguistically correct and do not match any + /// culture info. + /// public static CultureInfo InvariantCulture { get @@ -602,23 +579,17 @@ namespace System.Globalization } } - - //////////////////////////////////////////////////////////////////////// - // - // Parent - // - // Return the parent CultureInfo for the current instance. - // - //////////////////////////////////////////////////////////////////////// - + /// + /// Return the parent CultureInfo for the current instance. + /// public virtual CultureInfo Parent { get { - if (null == _parent) + if (_parent == null) { CultureInfo culture = null; - string parentName = _cultureData.SPARENT; + string parentName = _cultureData.ParentName; if (string.IsNullOrEmpty(parentName)) { @@ -642,21 +613,9 @@ namespace System.Globalization } } - public virtual int LCID - { - get - { - return _cultureData.ILANGUAGE; - } - } + public virtual int LCID => _cultureData.LCID; - public virtual int KeyboardLayoutId - { - get - { - return _cultureData.IINPUTLANGUAGEHANDLE; - } - } + public virtual int KeyboardLayoutId => _cultureData.KeyboardLayoutId; public static CultureInfo[] GetCultures(CultureTypes types) { @@ -669,14 +628,10 @@ namespace System.Globalization return CultureData.GetCultures(types); } - //////////////////////////////////////////////////////////////////////// - // - // Name - // - // Returns the full name of the CultureInfo. The name is in format like - // "en-US" This version does NOT include sort information in the name. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Returns the full name of the CultureInfo. The name is in format like + /// "en-US" This version does NOT include sort information in the name. + /// public virtual string Name { get @@ -684,24 +639,22 @@ namespace System.Globalization // We return non sorting name here. if (_nonSortName == null) { - _nonSortName = _cultureData.SNAME; - if (_nonSortName == null) - { - _nonSortName = string.Empty; - } + _nonSortName = _cultureData.Name ?? string.Empty; } return _nonSortName; } } - // This one has the sort information (ie: de-DE_phoneb) + /// + /// This one has the sort information (ie: de-DE_phoneb) + /// internal string SortName { get { if (_sortName == null) { - _sortName = _cultureData.SCOMPAREINFO; + _sortName = _cultureData.SortName; } return _sortName; @@ -725,100 +678,54 @@ namespace System.Globalization } } - //////////////////////////////////////////////////////////////////////// - // - // DisplayName - // - // Returns the full name of the CultureInfo in the localized language. - // For example, if the localized language of the runtime is Spanish and the CultureInfo is - // US English, "Ingles (Estados Unidos)" will be returned. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Returns the full name of the CultureInfo in the localized language. + /// For example, if the localized language of the runtime is Spanish and the CultureInfo is + /// US English, "Ingles (Estados Unidos)" will be returned. + /// public virtual string DisplayName { get { Debug.Assert(_name != null, "[CultureInfo.DisplayName] Always expect _name to be set"); - - return _cultureData.SLOCALIZEDDISPLAYNAME; - } - } - - //////////////////////////////////////////////////////////////////////// - // - // GetNativeName - // - // Returns the full name of the CultureInfo in the native language. - // For example, if the CultureInfo is US English, "English - // (United States)" will be returned. - // - //////////////////////////////////////////////////////////////////////// - public virtual string NativeName - { - get - { - return _cultureData.SNATIVEDISPLAYNAME; - } - } - - //////////////////////////////////////////////////////////////////////// - // - // GetEnglishName - // - // Returns the full name of the CultureInfo in English. - // For example, if the CultureInfo is US English, "English - // (United States)" will be returned. - // - //////////////////////////////////////////////////////////////////////// - public virtual string EnglishName - { - get - { - return _cultureData.SENGDISPLAYNAME; + return _cultureData.DisplayName; } } - // ie: en - public virtual string TwoLetterISOLanguageName - { - get - { - return _cultureData.SISO639LANGNAME; - } - } - - // ie: eng - public virtual string ThreeLetterISOLanguageName - { - get - { - return _cultureData.SISO639LANGNAME2; - } - } + /// + /// Returns the full name of the CultureInfo in the native language. + /// For example, if the CultureInfo is US English, "English + /// (United States)" will be returned. + /// + public virtual string NativeName => _cultureData.NativeName; + + /// + /// Returns the full name of the CultureInfo in English. + /// For example, if the CultureInfo is US English, "English + /// (United States)" will be returned. + /// + public virtual string EnglishName => _cultureData.EnglishName; + + /// + /// ie: en + /// + public virtual string TwoLetterISOLanguageName => _cultureData.TwoLetterISOLanguageName; + + /// + /// ie: eng + /// + public virtual string ThreeLetterISOLanguageName => _cultureData.ThreeLetterISOLanguageName; + + /// + /// Returns the 3 letter windows language name for the current instance. eg: "ENU" + /// The ISO names are much preferred + /// + public virtual string ThreeLetterWindowsLanguageName => _cultureData.ThreeLetterWindowsLanguageName; - //////////////////////////////////////////////////////////////////////// - // - // ThreeLetterWindowsLanguageName - // - // Returns the 3 letter windows language name for the current instance. eg: "ENU" - // The ISO names are much preferred - // - //////////////////////////////////////////////////////////////////////// - public virtual string ThreeLetterWindowsLanguageName - { - get - { - return _cultureData.SABBREVLANGNAME; - } - } - - //////////////////////////////////////////////////////////////////////// - // // CompareInfo Read-Only Property - // - // Gets the CompareInfo for this culture. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Gets the CompareInfo for this culture. + /// public virtual CompareInfo CompareInfo { get @@ -835,13 +742,9 @@ namespace System.Globalization } } - //////////////////////////////////////////////////////////////////////// - // - // TextInfo - // - // Gets the TextInfo for this culture. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Gets the TextInfo for this culture. + /// public virtual TextInfo TextInfo { get @@ -857,81 +760,50 @@ namespace System.Globalization } } - //////////////////////////////////////////////////////////////////////// - // - // Equals - // - // Implements object.Equals(). Returns a boolean indicating whether - // or not object refers to the same CultureInfo as the current instance. - // - //////////////////////////////////////////////////////////////////////// - - public override bool Equals(object value) { if (object.ReferenceEquals(this, value)) + { return true; + } if (value is CultureInfo that) { // using CompareInfo to verify the data passed through the constructor // CultureInfo(String cultureName, String textAndCompareCultureName) - - return this.Name.Equals(that.Name) && this.CompareInfo.Equals(that.CompareInfo); + return Name.Equals(that.Name) && CompareInfo.Equals(that.CompareInfo); } return false; } - - //////////////////////////////////////////////////////////////////////// - // - // GetHashCode - // - // Implements object.GetHashCode(). Returns the hash code for the - // CultureInfo. The hash code is guaranteed to be the same for CultureInfo A - // and B where A.Equals(B) is true. - // - //////////////////////////////////////////////////////////////////////// - public override int GetHashCode() { - return this.Name.GetHashCode() + this.CompareInfo.GetHashCode(); + return Name.GetHashCode() + CompareInfo.GetHashCode(); } - //////////////////////////////////////////////////////////////////////// - // - // ToString - // - // Implements object.ToString(). Returns the name of the CultureInfo, - // eg. "de-DE_phoneb", "en-US", or "fj-FJ". - // - //////////////////////////////////////////////////////////////////////// - - - public override string ToString() - { - return _name; - } - + /// + /// Implements object.ToString(). Returns the name of the CultureInfo, + /// eg. "de-DE_phoneb", "en-US", or "fj-FJ". + /// + public override string ToString() => _name; public virtual object GetFormat(Type formatType) { if (formatType == typeof(NumberFormatInfo)) + { return NumberFormat; + } if (formatType == typeof(DateTimeFormatInfo)) + { return DateTimeFormat; + } + return null; } - public virtual bool IsNeutralCulture - { - get - { - return _cultureData.IsNeutralCulture; - } - } + public virtual bool IsNeutralCulture => _cultureData.IsNeutralCulture; public CultureTypes CultureTypes { @@ -940,9 +812,13 @@ namespace System.Globalization CultureTypes types = 0; if (_cultureData.IsNeutralCulture) + { types |= CultureTypes.NeutralCultures; + } else + { types |= CultureTypes.SpecificCultures; + } types |= _cultureData.IsWin32Installed ? CultureTypes.InstalledWin32Cultures : 0; @@ -965,7 +841,7 @@ namespace System.Globalization if (_numInfo == null) { NumberFormatInfo temp = new NumberFormatInfo(_cultureData); - temp.isReadOnly = _isReadOnly; + temp._isReadOnly = _isReadOnly; Interlocked.CompareExchange(ref _numInfo, temp, null); } return _numInfo; @@ -976,19 +852,16 @@ namespace System.Globalization { throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); _numInfo = value; } } - //////////////////////////////////////////////////////////////////////// - // - // GetDateTimeFormatInfo - // - // Create a DateTimeFormatInfo, and fill in the properties according to - // the CultureID. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Create a DateTimeFormatInfo, and fill in the properties according to + /// the CultureID. + /// public virtual DateTimeFormatInfo DateTimeFormat { get @@ -1009,6 +882,7 @@ namespace System.Globalization { throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); _dateTimeInfo = value; } @@ -1021,7 +895,7 @@ namespace System.Globalization s_userDefaultUICulture = GetUserDefaultUICulture(); RegionInfo.s_currentRegionInfo = null; -#pragma warning disable 0618 // disable the obsolete warning +#pragma warning disable 0618 // disable the obsolete warning TimeZone.ResetTimeZone(); #pragma warning restore 0618 TimeZoneInfo.ClearCachedData(); @@ -1031,25 +905,29 @@ namespace System.Globalization CultureData.ClearCachedData(); } - /*=================================GetCalendarInstance========================== - **Action: Map a Win32 CALID to an instance of supported calendar. - **Returns: An instance of calendar. - **Arguments: calType The Win32 CALID - **Exceptions: - ** Shouldn't throw exception since the calType value is from our data table or from Win32 registry. - ** If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar. - ============================================================================*/ + /// + /// Map a Win32 CALID to an instance of supported calendar. + /// + /// + /// Shouldn't throw exception since the calType value is from our data + /// table or from Win32 registry. + /// If we are in trouble (like getting a weird value from Win32 + /// registry), just return the GregorianCalendar. + /// internal static Calendar GetCalendarInstance(CalendarId calType) { if (calType == CalendarId.GREGORIAN) { return new GregorianCalendar(); } + return GetCalendarInstanceRare(calType); } - //This function exists as a shortcut to prevent us from loading all of the non-gregorian - //calendars unless they're required. + /// + /// This function exists as a shortcut to prevent us from loading all of the non-gregorian + /// calendars unless they're required. + /// internal static Calendar GetCalendarInstanceRare(CalendarId calType) { Debug.Assert(calType != CalendarId.GREGORIAN, "calType!=CalendarId.GREGORIAN"); @@ -1082,13 +960,10 @@ namespace System.Globalization return new GregorianCalendar(); } - /*=================================Calendar========================== - **Action: Return/set the default calendar used by this culture. - ** This value can be overridden by regional option if this is a current culture. - **Returns: - **Arguments: - **Exceptions: - ============================================================================*/ + /// + /// Return/set the default calendar used by this culture. + /// This value can be overridden by regional option if this is a current culture. + /// public virtual Calendar Calendar { get @@ -1100,7 +975,7 @@ namespace System.Globalization // from registry if this is a user default culture. Calendar newObj = _cultureData.DefaultCalendar; - System.Threading.Interlocked.MemoryBarrier(); + Interlocked.MemoryBarrier(); newObj.SetReadOnlyState(_isReadOnly); _calendar = newObj; } @@ -1108,21 +983,14 @@ namespace System.Globalization } } - /*=================================OptionCalendars========================== - **Action: Return an array of the optional calendar for this culture. - **Returns: an array of Calendar. - **Arguments: - **Exceptions: - ============================================================================*/ - - + /// + /// Return an array of the optional calendar for this culture. + /// public virtual Calendar[] OptionalCalendars { get { - // // This property always returns a new copy of the calendar array. - // CalendarId[] calID = _cultureData.CalendarIds; Calendar[] cals = new Calendar[calID.Length]; for (int i = 0; i < cals.Length; i++) @@ -1133,13 +1001,7 @@ namespace System.Globalization } } - public bool UseUserOverride - { - get - { - return _cultureData.UseUserOverride; - } - } + public bool UseUserOverride => _cultureData.UseUserOverride; public CultureInfo GetConsoleFallbackUICulture() { @@ -1158,8 +1020,8 @@ namespace System.Globalization CultureInfo ci = (CultureInfo)MemberwiseClone(); ci._isReadOnly = false; - //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless - //they've already been allocated. If this is a derived type, we'll take a more generic codepath. + // If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless + // they've already been allocated. If this is a derived type, we'll take a more generic codepath. if (!_isInherited) { if (_dateTimeInfo != null) @@ -1205,8 +1067,8 @@ namespace System.Globalization if (!ci.IsNeutralCulture) { - //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless - //they've already been allocated. If this is a derived type, we'll take a more generic codepath. + // If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless + // they've already been allocated. If this is a derived type, we'll take a more generic codepath. if (!ci._isInherited) { if (ci._dateTimeInfo != null) @@ -1243,13 +1105,7 @@ namespace System.Globalization } - public bool IsReadOnly - { - get - { - return _isReadOnly; - } - } + public bool IsReadOnly => _isReadOnly; private void VerifyWritable() { @@ -1259,16 +1115,20 @@ namespace System.Globalization } } - // For resource lookup, we consider a culture the invariant culture by name equality. - // We perform this check frequently during resource lookup, so adding a property for - // improved readability. + /// + /// For resource lookup, we consider a culture the invariant culture by name equality. + /// We perform this check frequently during resource lookup, so adding a property for + /// improved readability. + /// internal bool HasInvariantCultureName { - get { return Name == CultureInfo.InvariantCulture.Name; } + get => Name == CultureInfo.InvariantCulture.Name; } - // 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. + /// + /// 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. @@ -1384,7 +1244,7 @@ namespace System.Globalization { tempNameHT[newName] = retval; } - } + } else { lock (_lock) @@ -1407,8 +1267,10 @@ namespace System.Globalization return retval; } - // Gets a cached copy of the specified culture from an internal hashtable (or creates it - // if not found). (LCID version)... use named version + /// + /// Gets a cached copy of the specified culture from an internal + /// hashtable (or creates it if not found). (LCID version) + /// public static CultureInfo GetCultureInfo(int culture) { // Must check for -1 now since the helper function uses the value to signal @@ -1426,8 +1288,10 @@ namespace System.Globalization return retval; } - // Gets a cached copy of the specified culture from an internal hashtable (or creates it - // if not found). (Named version) + /// + /// Gets a cached copy of the specified culture from an internal + /// hashtable (or creates it if not found). (Named version) + /// public static CultureInfo GetCultureInfo(string name) { // Make sure we have a valid, non-zero length string as name @@ -1445,16 +1309,16 @@ namespace System.Globalization return retval; } - // Gets a cached copy of the specified culture from an internal hashtable (or creates it - // if not found). + /// + /// Gets a cached copy of the specified culture from an internal + /// hashtable (or creates it if not found). + /// public static CultureInfo GetCultureInfo(string name, string altName) { - // Make sure we have a valid, non-zero length string as name if (name == null) { throw new ArgumentNullException(nameof(name)); } - if (altName == null) { throw new ArgumentNullException(nameof(altName)); @@ -1469,7 +1333,6 @@ namespace System.Globalization return retval; } - // This function is deprecated, we don't like it public static CultureInfo GetCultureInfoByIetfLanguageTag(string name) { // Disallow old zh-CHT/zh-CHS names diff --git a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs index bb2ddf0..5bf9f4e 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs @@ -282,7 +282,7 @@ namespace System if (dtfi.Calendar.IsLeapYear(dtfi.Calendar.GetYear(time))) { // This month is in a leap year - return (dtfi.internalGetMonthName(month, MonthNameStyles.LeapYear, (repeatCount == 3))); + return dtfi.InternalGetMonthName(month, MonthNameStyles.LeapYear, (repeatCount == 3)); } // This is in a regular year. if (month >= 7) @@ -630,7 +630,7 @@ namespace System if ((dtfi.FormatFlags & DateTimeFormatFlags.UseGenitiveMonth) != 0) { result.Append( - dtfi.internalGetMonthName( + dtfi.InternalGetMonthName( month, IsUseGenitiveForm(format, i, tokenLen, 'd') ? MonthNameStyles.Genitive : MonthNameStyles.Regular, tokenLen == 3)); diff --git a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs index 8123d37..310771d 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs @@ -8,13 +8,13 @@ using System.Runtime.CompilerServices; namespace System.Globalization { - // - // Flags used to indicate different styles of month names. - // This is an internal flag used by internalGetMonthName(). - // Use flag here in case that we need to provide a combination of these styles - // (such as month name of a leap year in genitive form. Not likely for now, - // but would like to keep the option open). - // + /// + /// Flags used to indicate different styles of month names. + /// This is an internal flag used by internalGetMonthName(). + /// Use flag here in case that we need to provide a combination of these styles + /// (such as month name of a leap year in genitive form. Not likely for now, + /// but would like to keep the option open). + /// [Flags] internal enum MonthNameStyles @@ -24,15 +24,15 @@ namespace System.Globalization LeapYear = 0x00000002, } - // - // Flags used to indicate special rule used in parsing/formatting - // for a specific DateTimeFormatInfo instance. - // This is an internal flag. - // - // This flag is different from MonthNameStyles because this flag - // can be expanded to accommodate parsing behaviors like CJK month names - // or alternative month names, etc. - + /// + /// Flags used to indicate special rule used in parsing/formatting + /// for a specific DateTimeFormatInfo instance. + /// This is an internal flag. + /// + /// This flag is different from MonthNameStyles because this flag + /// can be expanded to accommodate parsing behaviors like CJK month names + /// or alternative month names, etc. + /// [Flags] internal enum DateTimeFormatFlags { @@ -47,7 +47,6 @@ namespace System.Globalization NotInitialized = -1, } - public sealed class DateTimeFormatInfo : IFormatProvider, ICloneable { // cache for the invariant culture. @@ -69,10 +68,6 @@ namespace System.Globalization // Culture matches current DTFI. mainly used for string comparisons during parsing. private CultureInfo _cultureInfo = null; - // - // Caches for various properties. - // - private string amDesignator = null; private string pmDesignator = null; @@ -84,37 +79,29 @@ namespace System.Globalization private string timeSeparator = null; // derived from long time (whidbey expects, arrowhead doesn't) private string monthDayPattern = null; - // added in .NET Framework Release {2.0SP1/3.0SP1/3.5RTM} private string dateTimeOffsetPattern = null; - // - // The following are constant values. - // private const string rfc1123Pattern = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'"; // The sortable pattern is based on ISO 8601. private const string sortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss"; private const string universalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'"; - // - // The following are affected by calendar settings. - // private Calendar calendar = null; private int firstDayOfWeek = -1; private int calendarWeekRule = -1; - private string fullDateTimePattern = null; // long date + long time (whidbey expects, arrowhead doesn't) private string[] abbreviatedDayNames = null; - private string[] m_superShortDayNames = null; private string[] dayNames = null; private string[] abbreviatedMonthNames = null; private string[] monthNames = null; + // Cache the genitive month names that we retrieve from the data table. private string[] genitiveMonthNames = null; @@ -124,7 +111,6 @@ namespace System.Globalization private string[] m_genitiveAbbreviatedMonthNames = null; // Cache the month names of a leap year that we retrieve from the data table. - private string[] leapYearMonthNames = null; // For our "patterns" arrays we have 2 variables, a string and a string[] @@ -164,17 +150,7 @@ namespace System.Globalization private DateTimeFormatFlags formatFlags = DateTimeFormatFlags.NotInitialized; - private string CultureName - { - get - { - if (_name == null) - { - _name = _cultureData.CultureName; - } - return (_name); - } - } + private string CultureName => _name ?? (_name = _cultureData.CultureName); private CultureInfo Culture { @@ -182,116 +158,98 @@ namespace System.Globalization { if (_cultureInfo == null) { - _cultureInfo = CultureInfo.GetCultureInfo(this.CultureName); + _cultureInfo = CultureInfo.GetCultureInfo(CultureName); } return _cultureInfo; } } - // TODO: This ignores other cultures that might want to do something similar private string LanguageName { get { if (_langName == null) { - _langName = _cultureData.SISO639LANGNAME; + _langName = _cultureData.TwoLetterISOLanguageName; } - return (_langName); + return _langName; } } - //////////////////////////////////////////////////////////////////////////// - // - // Create an array of string which contains the abbreviated day names. - // - //////////////////////////////////////////////////////////////////////////// + /// + /// Create an array of string which contains the abbreviated day names. + /// + private string[] InternalGetAbbreviatedDayOfWeekNames() => abbreviatedDayNames ?? InternalGetAbbreviatedDayOfWeekNamesCore(); - private string[] internalGetAbbreviatedDayOfWeekNames() => this.abbreviatedDayNames ?? internalGetAbbreviatedDayOfWeekNamesCore(); [MethodImpl(MethodImplOptions.NoInlining)] - private string[] internalGetAbbreviatedDayOfWeekNamesCore() + private string[] InternalGetAbbreviatedDayOfWeekNamesCore() { // Get the abbreviated day names for our current calendar - this.abbreviatedDayNames = _cultureData.AbbreviatedDayNames(Calendar.ID); - Debug.Assert(this.abbreviatedDayNames.Length == 7, "[DateTimeFormatInfo.GetAbbreviatedDayOfWeekNames] Expected 7 day names in a week"); - return this.abbreviatedDayNames; + abbreviatedDayNames = _cultureData.AbbreviatedDayNames(Calendar.ID); + Debug.Assert(abbreviatedDayNames.Length == 7, "[DateTimeFormatInfo.GetAbbreviatedDayOfWeekNames] Expected 7 day names in a week"); + return abbreviatedDayNames; } - //////////////////////////////////////////////////////////////////////// - // - // Action: Returns the string array of the one-letter day of week names. - // Returns: - // an array of one-letter day of week names - // Arguments: - // None - // Exceptions: - // None - // - //////////////////////////////////////////////////////////////////////// + /// + /// Returns the string array of the one-letter day of week names. + /// + private string[] InternalGetSuperShortDayNames() => m_superShortDayNames ?? InternalGetSuperShortDayNamesCore(); - private string[] internalGetSuperShortDayNames() => this.m_superShortDayNames ?? internalGetSuperShortDayNamesCore(); [MethodImpl(MethodImplOptions.NoInlining)] - private string[] internalGetSuperShortDayNamesCore() + private string[] InternalGetSuperShortDayNamesCore() { // Get the super short day names for our current calendar - this.m_superShortDayNames = _cultureData.SuperShortDayNames(Calendar.ID); - Debug.Assert(this.m_superShortDayNames.Length == 7, "[DateTimeFormatInfo.internalGetSuperShortDayNames] Expected 7 day names in a week"); - return this.m_superShortDayNames; + m_superShortDayNames = _cultureData.SuperShortDayNames(Calendar.ID); + Debug.Assert(m_superShortDayNames.Length == 7, "[DateTimeFormatInfo.InternalGetSuperShortDayNames] Expected 7 day names in a week"); + return m_superShortDayNames; } - //////////////////////////////////////////////////////////////////////////// - // - // Create an array of string which contains the day names. - // - //////////////////////////////////////////////////////////////////////////// + /// + /// Create an array of string which contains the day names. + /// + private string[] InternalGetDayOfWeekNames() => dayNames ?? InternalGetDayOfWeekNamesCore(); - private string[] internalGetDayOfWeekNames() => this.dayNames ?? internalGetDayOfWeekNamesCore(); [MethodImpl(MethodImplOptions.NoInlining)] - private string[] internalGetDayOfWeekNamesCore() + private string[] InternalGetDayOfWeekNamesCore() { // Get the day names for our current calendar - this.dayNames = _cultureData.DayNames(Calendar.ID); - Debug.Assert(this.dayNames.Length == 7, "[DateTimeFormatInfo.GetDayOfWeekNames] Expected 7 day names in a week"); - return this.dayNames; + dayNames = _cultureData.DayNames(Calendar.ID); + Debug.Assert(dayNames.Length == 7, "[DateTimeFormatInfo.GetDayOfWeekNames] Expected 7 day names in a week"); + return dayNames; } - //////////////////////////////////////////////////////////////////////////// - // - // Create an array of string which contains the abbreviated month names. - // - //////////////////////////////////////////////////////////////////////////// + /// + /// Create an array of string which contains the abbreviated month names. + /// + private string[] InternalGetAbbreviatedMonthNames() => abbreviatedMonthNames ?? InternalGetAbbreviatedMonthNamesCore(); - private string[] internalGetAbbreviatedMonthNames() => this.abbreviatedMonthNames ?? internalGetAbbreviatedMonthNamesCore(); [MethodImpl(MethodImplOptions.NoInlining)] - private string[] internalGetAbbreviatedMonthNamesCore() + private string[] InternalGetAbbreviatedMonthNamesCore() { // Get the month names for our current calendar - this.abbreviatedMonthNames = _cultureData.AbbreviatedMonthNames(Calendar.ID); - Debug.Assert(this.abbreviatedMonthNames.Length == 12 || this.abbreviatedMonthNames.Length == 13, + abbreviatedMonthNames = _cultureData.AbbreviatedMonthNames(Calendar.ID); + Debug.Assert(abbreviatedMonthNames.Length == 12 || abbreviatedMonthNames.Length == 13, "[DateTimeFormatInfo.GetAbbreviatedMonthNames] Expected 12 or 13 month names in a year"); - return this.abbreviatedMonthNames; + return abbreviatedMonthNames; } - //////////////////////////////////////////////////////////////////////////// - // - // Create an array of string which contains the month names. - // - //////////////////////////////////////////////////////////////////////////// + /// + /// Create an array of string which contains the month names. + /// + private string[] InternalGetMonthNames() => monthNames ?? internalGetMonthNamesCore(); - private string[] internalGetMonthNames() => this.monthNames ?? internalGetMonthNamesCore(); [MethodImpl(MethodImplOptions.NoInlining)] private string[] internalGetMonthNamesCore() { // Get the month names for our current calendar - this.monthNames = _cultureData.MonthNames(Calendar.ID); - Debug.Assert(this.monthNames.Length == 12 || this.monthNames.Length == 13, + monthNames = _cultureData.MonthNames(Calendar.ID); + Debug.Assert(monthNames.Length == 12 || monthNames.Length == 13, "[DateTimeFormatInfo.GetMonthNames] Expected 12 or 13 month names in a year"); - return this.monthNames; + return monthNames; } - // // Invariant DateTimeFormatInfo doesn't have user-overriden values // Default calendar is gregorian public DateTimeFormatInfo() @@ -307,7 +265,7 @@ namespace System.Globalization // Remember our culture _cultureData = cultureData; - this.Calendar = cal; + Calendar = cal; } private void InitializeOverridableProperties(CultureData cultureData, CalendarId calendarId) @@ -315,35 +273,52 @@ namespace System.Globalization Debug.Assert(cultureData != null); Debug.Assert(calendarId != CalendarId.UNINITIALIZED_VALUE, "[DateTimeFormatInfo.Populate] Expected initalized calendarId"); - if (this.firstDayOfWeek == -1) { this.firstDayOfWeek = cultureData.IFIRSTDAYOFWEEK; } - if (this.calendarWeekRule == -1) { this.calendarWeekRule = cultureData.IFIRSTWEEKOFYEAR; } + if (firstDayOfWeek == -1) + { + firstDayOfWeek = cultureData.FirstDayOfWeek; + } + if (calendarWeekRule == -1) + { + calendarWeekRule = cultureData.CalendarWeekRule; + } - if (this.amDesignator == null) { this.amDesignator = cultureData.SAM1159; } - if (this.pmDesignator == null) { this.pmDesignator = cultureData.SPM2359; } - if (this.timeSeparator == null) { this.timeSeparator = cultureData.TimeSeparator; } - if (this.dateSeparator == null) { this.dateSeparator = cultureData.DateSeparator(calendarId); } + if (amDesignator == null) + { + amDesignator = cultureData.AMDesignator; + } + if (pmDesignator == null) + { + pmDesignator = cultureData.PMDesignator; + } + if (timeSeparator == null) + { + timeSeparator = cultureData.TimeSeparator; + } + if (dateSeparator == null) + { + dateSeparator = cultureData.DateSeparator(calendarId); + } - this.allLongTimePatterns = _cultureData.LongTimes; - Debug.Assert(this.allLongTimePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some long time patterns"); + allLongTimePatterns = _cultureData.LongTimes; + Debug.Assert(allLongTimePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some long time patterns"); - this.allShortTimePatterns = _cultureData.ShortTimes; - Debug.Assert(this.allShortTimePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some short time patterns"); + allShortTimePatterns = _cultureData.ShortTimes; + Debug.Assert(allShortTimePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some short time patterns"); - this.allLongDatePatterns = cultureData.LongDates(calendarId); - Debug.Assert(this.allLongDatePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some long date patterns"); + allLongDatePatterns = cultureData.LongDates(calendarId); + Debug.Assert(allLongDatePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some long date patterns"); - this.allShortDatePatterns = cultureData.ShortDates(calendarId); - Debug.Assert(this.allShortDatePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some short date patterns"); + allShortDatePatterns = cultureData.ShortDates(calendarId); + Debug.Assert(allShortDatePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some short date patterns"); - this.allYearMonthPatterns = cultureData.YearMonths(calendarId); - Debug.Assert(this.allYearMonthPatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some year month patterns"); + allYearMonthPatterns = cultureData.YearMonths(calendarId); + Debug.Assert(allYearMonthPatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some year month patterns"); } - // Returns a default DateTimeFormatInfo that will be universally - // supported and constant irrespective of the current culture. - // Used by FromString methods. - // - + /// + /// Returns a default DateTimeFormatInfo that will be universally + /// supported and constant irrespective of the current culture. + /// public static DateTimeFormatInfo InvariantInfo { get @@ -355,12 +330,13 @@ namespace System.Globalization info._isReadOnly = true; s_invariantInfo = info; } - return (s_invariantInfo); + return s_invariantInfo; } } - // Returns the current culture's DateTimeFormatInfo. Used by Parse methods. - // + /// + /// Returns the current culture's DateTimeFormatInfo. + /// public static DateTimeFormatInfo CurrentInfo { @@ -388,42 +364,42 @@ namespace System.Globalization public object GetFormat(Type formatType) { - return (formatType == typeof(DateTimeFormatInfo) ? this : null); + return formatType == typeof(DateTimeFormatInfo) ? this : null; } - public object Clone() { DateTimeFormatInfo n = (DateTimeFormatInfo)MemberwiseClone(); // We can use the data member calendar in the setter, instead of the property Calendar, // since the cloned copy should have the same state as the original copy. - n.calendar = (Calendar)this.Calendar.Clone(); + n.calendar = (Calendar)Calendar.Clone(); n._isReadOnly = false; return n; } - public string AMDesignator { get { - if (this.amDesignator == null) + if (amDesignator == null) { - this.amDesignator = _cultureData.SAM1159; + amDesignator = _cultureData.AMDesignator; } - Debug.Assert(this.amDesignator != null, "DateTimeFormatInfo.AMDesignator, amDesignator != null"); - return (this.amDesignator); - } + Debug.Assert(amDesignator != null, "DateTimeFormatInfo.AMDesignator, amDesignator != null"); + return amDesignator; + } set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + ClearTokenHashTable(); amDesignator = value; } @@ -434,36 +410,35 @@ namespace System.Globalization { get { - Debug.Assert(this.calendar != null, "DateTimeFormatInfo.Calendar: calendar != null"); - return (this.calendar); + Debug.Assert(calendar != null, "DateTimeFormatInfo.Calendar: calendar != null"); + return calendar; } - set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { throw new ArgumentNullException(nameof(value)); } + if (value == calendar) { return; } - for (int i = 0; i < this.OptionalCalendars.Length; i++) + for (int i = 0; i < OptionalCalendars.Length; i++) { - if (this.OptionalCalendars[i] == value.ID) + if (OptionalCalendars[i] == value.ID) { // We can use this one, so do so. - // Clean related properties if we already had a calendar set if (calendar != null) { // clean related properties which are affected by the calendar setting, // so that they will be refreshed when they are accessed next time. - // - // These properites are in the order as appearing in calendar.xml. m_eraNames = null; m_abbrevEraNames = null; @@ -521,7 +496,7 @@ namespace System.Globalization } // The assigned calendar is not a valid calendar for this culture, throw - throw new ArgumentOutOfRangeException(nameof(value), SR.Argument_InvalidCalendar); + throw new ArgumentOutOfRangeException(nameof(value), value, SR.Argument_InvalidCalendar); } } @@ -529,29 +504,22 @@ namespace System.Globalization { get { - if (this.optionalCalendars == null) + if (optionalCalendars == null) { - this.optionalCalendars = _cultureData.CalendarIds; + optionalCalendars = _cultureData.CalendarIds; } - return (this.optionalCalendars); + return optionalCalendars; } } - /*=================================GetEra========================== - **Action: Get the era value by parsing the name of the era. - **Returns: The era value for the specified era name. - ** -1 if the name of the era is not valid or not supported. - **Arguments: eraName the name of the era. - **Exceptions: None. - ============================================================================*/ - - + /// + /// Get the era value by parsing the name of the era. + /// public int GetEra(string eraName) { if (eraName == null) { - throw new ArgumentNullException(nameof(eraName), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(eraName)); } // The Era Name and Abbreviated Era Name @@ -561,7 +529,7 @@ namespace System.Globalization // confer 85900 DTFI.GetEra("") should fail on all cultures if (eraName.Length == 0) { - return (-1); + return -1; } // The following is based on the assumption that the era value is starting from 1, and has a @@ -575,18 +543,18 @@ namespace System.Globalization // Compare the era name in a case-insensitive way for the appropriate culture. if (m_eraNames[i].Length > 0) { - if (this.Culture.CompareInfo.Compare(eraName, m_eraNames[i], CompareOptions.IgnoreCase) == 0) + if (Culture.CompareInfo.Compare(eraName, m_eraNames[i], CompareOptions.IgnoreCase) == 0) { - return (i + 1); + return i + 1; } } } for (int i = 0; i < AbbreviatedEraNames.Length; i++) { // Compare the abbreviated era name in a case-insensitive way for the appropriate culture. - if (this.Culture.CompareInfo.Compare(eraName, m_abbrevEraNames[i], CompareOptions.IgnoreCase) == 0) + if (Culture.CompareInfo.Compare(eraName, m_abbrevEraNames[i], CompareOptions.IgnoreCase) == 0) { - return (i + 1); + return i + 1; } } for (int i = 0; i < AbbreviatedEnglishEraNames.Length; i++) @@ -595,35 +563,28 @@ namespace System.Globalization // interesting characters. if (CompareInfo.Invariant.Compare(eraName, m_abbrevEnglishEraNames[i], CompareOptions.IgnoreCase) == 0) { - return (i + 1); + return i + 1; } } - return (-1); + return -1; } - internal string[] EraNames { get { - if (this.m_eraNames == null) + if (m_eraNames == null) { - this.m_eraNames = _cultureData.EraNames(Calendar.ID); ; + m_eraNames = _cultureData.EraNames(Calendar.ID); } - return (this.m_eraNames); + return m_eraNames; } } - /*=================================GetEraName========================== - **Action: Get the name of the era for the specified era value. - **Returns: The name of the specified era. - **Arguments: - ** era the era value. - **Exceptions: - ** ArguementException if the era valie is invalid. - ============================================================================*/ - - // Era names are 1 indexed + /// + /// Get the name of the era for the specified era value. + /// Era names are 1 indexed + /// public string GetEraName(int era) { if (era == Calendar.CurrentEra) @@ -636,31 +597,34 @@ namespace System.Globalization // If that ever changes, the code has to be changed. if ((--era) < EraNames.Length && (era >= 0)) { - return (m_eraNames[era]); + return m_eraNames[era]; } - throw new ArgumentOutOfRangeException(nameof(era), SR.ArgumentOutOfRange_InvalidEraValue); + + throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); } internal string[] AbbreviatedEraNames { get { - if (this.m_abbrevEraNames == null) + if (m_abbrevEraNames == null) { - this.m_abbrevEraNames = _cultureData.AbbrevEraNames(Calendar.ID); + m_abbrevEraNames = _cultureData.AbbrevEraNames(Calendar.ID); } - return (this.m_abbrevEraNames); + return m_abbrevEraNames; } } - // Era names are 1 indexed + /// + /// Era names are 1 indexed + /// public string GetAbbreviatedEraName(int era) { if (AbbreviatedEraNames.Length == 0) { // If abbreviation era name is not used in this culture, // return the full era name. - return (GetEraName(era)); + return GetEraName(era); } if (era == Calendar.CurrentEra) { @@ -668,26 +632,29 @@ namespace System.Globalization } if ((--era) < m_abbrevEraNames.Length && (era >= 0)) { - return (m_abbrevEraNames[era]); + return m_abbrevEraNames[era]; } - throw new ArgumentOutOfRangeException(nameof(era), SR.ArgumentOutOfRange_InvalidEraValue); + + throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); } internal string[] AbbreviatedEnglishEraNames { get { - if (this.m_abbrevEnglishEraNames == null) + if (m_abbrevEnglishEraNames == null) { Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.AbbreviatedEnglishEraNames] Expected Calendar.ID > 0"); - this.m_abbrevEnglishEraNames = _cultureData.AbbreviatedEnglishEraNames(Calendar.ID); + m_abbrevEnglishEraNames = _cultureData.AbbreviatedEnglishEraNames(Calendar.ID); } - return (this.m_abbrevEnglishEraNames); + return m_abbrevEnglishEraNames; } } - // Note that cultureData derives this from the short date format (unless someone's set this previously) - // Note that this property is quite undesirable. + /// + /// Note that cultureData derives this from the short date format (unless someone's set this previously) + /// Note that this property is quite undesirable. + /// public string DateSeparator { get @@ -696,18 +663,20 @@ namespace System.Globalization { dateSeparator = _cultureData.DateSeparator(Calendar.ID); } - Debug.Assert(this.dateSeparator != null, "DateTimeFormatInfo.DateSeparator, dateSeparator != null"); + Debug.Assert(dateSeparator != null, "DateTimeFormatInfo.DateSeparator, dateSeparator != null"); return dateSeparator; } set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - + } if (value == null) { - throw new ArgumentNullException(nameof(value), SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + ClearTokenHashTable(); dateSeparator = value; } @@ -717,29 +686,30 @@ namespace System.Globalization { get { - if (this.firstDayOfWeek == -1) + if (firstDayOfWeek == -1) { - this.firstDayOfWeek = _cultureData.IFIRSTDAYOFWEEK; + firstDayOfWeek = _cultureData.FirstDayOfWeek; } - Debug.Assert(this.firstDayOfWeek != -1, "DateTimeFormatInfo.FirstDayOfWeek, firstDayOfWeek != -1"); + Debug.Assert(firstDayOfWeek != -1, "DateTimeFormatInfo.FirstDayOfWeek, firstDayOfWeek != -1"); - return ((DayOfWeek)this.firstDayOfWeek); + return (DayOfWeek)firstDayOfWeek; } - set { if (IsReadOnly) - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - if (value >= DayOfWeek.Sunday && value <= DayOfWeek.Saturday) { - firstDayOfWeek = (int)value; + throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); } - else + + if (value < DayOfWeek.Sunday || value > DayOfWeek.Saturday) { throw new ArgumentOutOfRangeException( - nameof(value), SR.Format(SR.ArgumentOutOfRange_Range, - DayOfWeek.Sunday, DayOfWeek.Saturday)); + nameof(value), + value, + SR.Format(SR.ArgumentOutOfRange_Range, DayOfWeek.Sunday, DayOfWeek.Saturday)); } + + firstDayOfWeek = (int)value; } } @@ -747,28 +717,29 @@ namespace System.Globalization { get { - if (this.calendarWeekRule == -1) + if (calendarWeekRule == -1) { - this.calendarWeekRule = _cultureData.IFIRSTWEEKOFYEAR; + calendarWeekRule = _cultureData.CalendarWeekRule; } - Debug.Assert(this.calendarWeekRule != -1, "DateTimeFormatInfo.CalendarWeekRule, calendarWeekRule != -1"); - return ((CalendarWeekRule)this.calendarWeekRule); - } + Debug.Assert(calendarWeekRule != -1, "DateTimeFormatInfo.CalendarWeekRule, calendarWeekRule != -1"); + return (CalendarWeekRule)calendarWeekRule; + } set { if (IsReadOnly) - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - if (value >= CalendarWeekRule.FirstDay && value <= CalendarWeekRule.FirstFourDayWeek) { - calendarWeekRule = (int)value; + throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); } - else + if (value < CalendarWeekRule.FirstDay || value > CalendarWeekRule.FirstFourDayWeek) { throw new ArgumentOutOfRangeException( - nameof(value), SR.Format(SR.ArgumentOutOfRange_Range, - CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek)); + nameof(value), + value, + SR.Format(SR.ArgumentOutOfRange_Range, CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek)); } + + calendarWeekRule = (int)value; } } @@ -780,200 +751,203 @@ namespace System.Globalization { fullDateTimePattern = LongDatePattern + " " + LongTimePattern; } - return (fullDateTimePattern); + return fullDateTimePattern; } set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + fullDateTimePattern = value; } } - - // For our "patterns" arrays we have 2 variables, a string and a string[] - // - // The string[] contains the list of patterns, EXCEPT the default may not be included. - // The string contains the default pattern. - // When we initially construct our string[], we set the string to string[0] + /// + /// For our "patterns" arrays we have 2 variables, a string and a string[] + /// The string[] contains the list of patterns, EXCEPT the default may not be included. + /// The string contains the default pattern. + /// When we initially construct our string[], we set the string to string[0] + /// public string LongDatePattern { get { // Initialize our long date pattern from the 1st array value if not set - if (this.longDatePattern == null) + if (longDatePattern == null) { // Initialize our data - this.longDatePattern = this.UnclonedLongDatePatterns[0]; + longDatePattern = UnclonedLongDatePatterns[0]; } - return this.longDatePattern; + return longDatePattern; } - set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } // Remember the new string - this.longDatePattern = value; + longDatePattern = value; // Clear the token hash table ClearTokenHashTable(); // Clean up cached values that will be affected by this property. - this.fullDateTimePattern = null; + fullDateTimePattern = null; } } - // For our "patterns" arrays we have 2 variables, a string and a string[] - // - // The string[] contains the list of patterns, EXCEPT the default may not be included. - // The string contains the default pattern. - // When we initially construct our string[], we set the string to string[0] + /// + /// For our "patterns" arrays we have 2 variables, a string and a string[] + /// + /// The string[] contains the list of patterns, EXCEPT the default may not be included. + /// The string contains the default pattern. + /// When we initially construct our string[], we set the string to string[0] + /// public string LongTimePattern { get { // Initialize our long time pattern from the 1st array value if not set - if (this.longTimePattern == null) + if (longTimePattern == null) { // Initialize our data - this.longTimePattern = this.UnclonedLongTimePatterns[0]; + longTimePattern = UnclonedLongTimePatterns[0]; } - return this.longTimePattern; + return longTimePattern; } - set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } // Remember the new string - this.longTimePattern = value; + longTimePattern = value; // Clear the token hash table ClearTokenHashTable(); // Clean up cached values that will be affected by this property. - this.fullDateTimePattern = null; // Full date = long date + long Time - this.generalLongTimePattern = null; // General long date = short date + long Time - this.dateTimeOffsetPattern = null; + fullDateTimePattern = null; // Full date = long date + long Time + generalLongTimePattern = null; // General long date = short date + long Time + dateTimeOffsetPattern = null; } } - - // Note: just to be confusing there's only 1 month day pattern, not a whole list + /// + /// Just to be confusing there's only 1 month day pattern, not a whole list + /// public string MonthDayPattern { get { - if (this.monthDayPattern == null) + if (monthDayPattern == null) { Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.MonthDayPattern] Expected calID > 0"); - this.monthDayPattern = _cultureData.MonthDay(Calendar.ID); + monthDayPattern = _cultureData.MonthDay(Calendar.ID); } - Debug.Assert(this.monthDayPattern != null, "DateTimeFormatInfo.MonthDayPattern, monthDayPattern != null"); - return (this.monthDayPattern); - } + Debug.Assert(monthDayPattern != null, "DateTimeFormatInfo.MonthDayPattern, monthDayPattern != null"); + return monthDayPattern; + } set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } - this.monthDayPattern = value; + monthDayPattern = value; } } - public string PMDesignator { get { - if (this.pmDesignator == null) + if (pmDesignator == null) { - this.pmDesignator = _cultureData.SPM2359; + pmDesignator = _cultureData.PMDesignator; } - Debug.Assert(this.pmDesignator != null, "DateTimeFormatInfo.PMDesignator, pmDesignator != null"); - return (this.pmDesignator); - } + Debug.Assert(pmDesignator != null, "DateTimeFormatInfo.PMDesignator, pmDesignator != null"); + return pmDesignator; + } set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } - ClearTokenHashTable(); + ClearTokenHashTable(); pmDesignator = value; } } + public string RFC1123Pattern => rfc1123Pattern; - public string RFC1123Pattern - { - get - { - return (rfc1123Pattern); - } - } - - // For our "patterns" arrays we have 2 variables, a string and a string[] - // - // The string[] contains the list of patterns, EXCEPT the default may not be included. - // The string contains the default pattern. - // When we initially construct our string[], we set the string to string[0] + /// + /// For our "patterns" arrays we have 2 variables, a string and a string[] + /// + /// The string[] contains the list of patterns, EXCEPT the default may not be included. + /// The string contains the default pattern. + /// When we initially construct our string[], we set the string to string[0] + /// public string ShortDatePattern { get { // Initialize our short date pattern from the 1st array value if not set - if (this.shortDatePattern == null) + if (shortDatePattern == null) { // Initialize our data - this.shortDatePattern = this.UnclonedShortDatePatterns[0]; + shortDatePattern = UnclonedShortDatePatterns[0]; } - return this.shortDatePattern; + return shortDatePattern; } - set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_String); + { + throw new ArgumentNullException(nameof(value)); + } // Remember the new string - this.shortDatePattern = value; + shortDatePattern = value; // Clear the token hash table, note that even short dates could require this ClearTokenHashTable(); @@ -985,37 +959,38 @@ namespace System.Globalization } } - - // For our "patterns" arrays we have 2 variables, a string and a string[] - // - // The string[] contains the list of patterns, EXCEPT the default may not be included. - // The string contains the default pattern. - // When we initially construct our string[], we set the string to string[0] + /// + /// For our "patterns" arrays we have 2 variables, a string and a string[] + /// + /// The string[] contains the list of patterns, EXCEPT the default may not be included. + /// The string contains the default pattern. + /// When we initially construct our string[], we set the string to string[0] + /// public string ShortTimePattern { get { // Initialize our short time pattern from the 1st array value if not set - if (this.shortTimePattern == null) + if (shortTimePattern == null) { // Initialize our data - this.shortTimePattern = this.UnclonedShortTimePatterns[0]; + shortTimePattern = UnclonedShortTimePatterns[0]; } - return this.shortTimePattern; + return shortTimePattern; } - set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } // Remember the new string - this.shortTimePattern = value; + shortTimePattern = value; // Clear the token hash table, note that even short times could require this ClearTokenHashTable(); @@ -1025,22 +1000,14 @@ namespace System.Globalization } } + public string SortableDateTimePattern => sortableDateTimePattern; - public string SortableDateTimePattern - { - get - { - return (sortableDateTimePattern); - } - } - - /*=================================GeneralShortTimePattern===================== - **Property: Return the pattern for 'g' general format: shortDate + short time - **Note: This is used by DateTimeFormat.cs to get the pattern for 'g' - ** We put this internal property here so that we can avoid doing the - ** concatation every time somebody asks for the general format. - ==============================================================================*/ - + /// + /// Return the pattern for 'g' general format: shortDate + short time + /// This is used by DateTimeFormat.cs to get the pattern for 'g'. + /// We put this internal property here so that we can avoid doing the + /// concatation every time somebody asks for the general format. + /// internal string GeneralShortTimePattern { get @@ -1049,17 +1016,15 @@ namespace System.Globalization { generalShortTimePattern = ShortDatePattern + " " + ShortTimePattern; } - return (generalShortTimePattern); + return generalShortTimePattern; } } - /*=================================GeneralLongTimePattern===================== - **Property: Return the pattern for 'g' general format: shortDate + Long time - **Note: This is used by DateTimeFormat.cs to get the pattern for 'g' - ** We put this internal property here so that we can avoid doing the - ** concatation every time somebody asks for the general format. - ==============================================================================*/ - + /// + /// Return the pattern for 'g' general format: shortDate + Long time. + /// We put this internal property here so that we can avoid doing the + /// concatation every time somebody asks for the general format. + /// internal string GeneralLongTimePattern { get @@ -1068,17 +1033,14 @@ namespace System.Globalization { generalLongTimePattern = ShortDatePattern + " " + LongTimePattern; } - return (generalLongTimePattern); + return generalLongTimePattern; } } - /*=================================DateTimeOffsetPattern========================== - **Property: Return the default pattern DateTimeOffset : shortDate + long time + time zone offset - **Note: This is used by DateTimeFormat.cs to get the pattern for short Date + long time + time zone offset - ** We put this internal property here so that we can avoid doing the - ** concatation every time somebody uses this form - ==============================================================================*/ - + /// Return the default pattern DateTimeOffset : shortDate + long time + time zone offset. + /// This is used by DateTimeFormat.cs to get the pattern for short Date + long time + time zone offset + /// We put this internal property here so that we can avoid doing the + /// concatation every time somebody uses this form. internal string DateTimeOffsetPattern { get @@ -1134,12 +1096,14 @@ namespace System.Globalization dateTimeOffsetPattern = dateTimePattern; } - return (dateTimeOffsetPattern); + return dateTimeOffsetPattern; } } - // Note that cultureData derives this from the long time format (unless someone's set this previously) - // Note that this property is quite undesirable. + /// + /// Note that cultureData derives this from the long time format (unless someone's set this previously) + /// Note that this property is quite undesirable. + /// public string TimeSeparator { get @@ -1148,73 +1112,68 @@ namespace System.Globalization { timeSeparator = _cultureData.TimeSeparator; } - Debug.Assert(this.timeSeparator != null, "DateTimeFormatInfo.TimeSeparator, timeSeparator != null"); - return (timeSeparator); + Debug.Assert(timeSeparator != null, "DateTimeFormatInfo.TimeSeparator, timeSeparator != null"); + return timeSeparator; } - set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - + } if (value == null) { - throw new ArgumentNullException(nameof(value), SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } ClearTokenHashTable(); - timeSeparator = value; } } - public string UniversalSortableDateTimePattern - { - get - { - return (universalSortableDateTimePattern); - } - } + public string UniversalSortableDateTimePattern => universalSortableDateTimePattern; - // For our "patterns" arrays we have 2 variables, a string and a string[] - // - // The string[] contains the list of patterns, EXCEPT the default may not be included. - // The string contains the default pattern. - // When we initially construct our string[], we set the string to string[0] + /// + /// For our "patterns" arrays we have 2 variables, a string and a string[] + /// + /// The string[] contains the list of patterns, EXCEPT the default may not be included. + /// The string contains the default pattern. + /// When we initially construct our string[], we set the string to string[0] + /// public string YearMonthPattern { get { // Initialize our year/month pattern from the 1st array value if not set - if (this.yearMonthPattern == null) + if (yearMonthPattern == null) { // Initialize our data - this.yearMonthPattern = this.UnclonedYearMonthPatterns[0]; + yearMonthPattern = UnclonedYearMonthPatterns[0]; } - return this.yearMonthPattern; + return yearMonthPattern; } - set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } // Remember the new string - this.yearMonthPattern = value; + yearMonthPattern = value; // Clear the token hash table, note that even short times could require this ClearTokenHashTable(); } } - // - // Check if a string array contains a null value, and throw ArgumentNullException with parameter name "value" - // + /// + /// Check if a string array contains a null value, and throw ArgumentNullException with parameter name "value" + /// private static void CheckNullValue(string[] values, int length) { Debug.Assert(values != null, "value != null"); @@ -1223,33 +1182,29 @@ namespace System.Globalization { if (values[i] == null) { - throw new ArgumentNullException("value", - SR.ArgumentNull_ArrayValue); + throw new ArgumentNullException("value", SR.ArgumentNull_ArrayValue); } } } - public string[] AbbreviatedDayNames { - get - { - return ((string[])internalGetAbbreviatedDayOfWeekNames().Clone()); - } - + get => (string[])InternalGetAbbreviatedDayOfWeekNames().Clone(); set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_Array); + throw new ArgumentNullException(nameof(value)); } if (value.Length != 7) { throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), nameof(value)); } + CheckNullValue(value, value.Length); ClearTokenHashTable(); @@ -1257,53 +1212,50 @@ namespace System.Globalization } } - // Returns the string array of the one-letter day of week names. + /// + /// Returns the string array of the one-letter day of week names. + /// public string[] ShortestDayNames { - get - { - return ((string[])internalGetSuperShortDayNames().Clone()); - } - + get => (string[])InternalGetSuperShortDayNames().Clone(); set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_Array); + throw new ArgumentNullException(nameof(value)); } if (value.Length != 7) { throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), nameof(value)); } + CheckNullValue(value, value.Length); - this.m_superShortDayNames = value; + m_superShortDayNames = value; } } - public string[] DayNames { - get - { - return ((string[])internalGetDayOfWeekNames().Clone()); - } - + get => (string[])InternalGetDayOfWeekNames().Clone(); set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_Array); + throw new ArgumentNullException(nameof(value)); } if (value.Length != 7) { throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), nameof(value)); } + CheckNullValue(value, value.Length); ClearTokenHashTable(); @@ -1311,54 +1263,48 @@ namespace System.Globalization } } - public string[] AbbreviatedMonthNames { - get - { - return ((string[])internalGetAbbreviatedMonthNames().Clone()); - } - + get => (string[])InternalGetAbbreviatedMonthNames().Clone(); set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_Array); + throw new ArgumentNullException(nameof(value)); } if (value.Length != 13) { throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), nameof(value)); } + CheckNullValue(value, value.Length - 1); ClearTokenHashTable(); abbreviatedMonthNames = value; } } - public string[] MonthNames { - get - { - return ((string[])internalGetMonthNames().Clone()); - } - + get => (string[])InternalGetMonthNames().Clone(); set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_Array); + throw new ArgumentNullException(nameof(value)); } if (value.Length != 13) { throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), nameof(value)); } + CheckNullValue(value, value.Length - 1); monthNames = value; ClearTokenHashTable(); @@ -1369,147 +1315,125 @@ namespace System.Globalization // U+00a0 is non-breaking space. private static readonly char[] s_monthSpaces = { ' ', '\u00a0' }; - internal bool HasSpacesInMonthNames - { - get - { - return (FormatFlags & DateTimeFormatFlags.UseSpacesInMonthNames) != 0; - } - } - - internal bool HasSpacesInDayNames - { - get - { - return (FormatFlags & DateTimeFormatFlags.UseSpacesInDayNames) != 0; - } - } + internal bool HasSpacesInMonthNames =>(FormatFlags & DateTimeFormatFlags.UseSpacesInMonthNames) != 0; + internal bool HasSpacesInDayNames => (FormatFlags & DateTimeFormatFlags.UseSpacesInDayNames) != 0; - // - // internalGetMonthName - // - // Actions: Return the month name using the specified MonthNameStyles in either abbreviated form - // or full form. - // Arguments: - // month - // style To indicate a form like regular/genitive/month name in a leap year. - // abbreviated When true, return abbreviated form. Otherwise, return a full form. - // Exceptions: - // ArgumentOutOfRangeException When month name is invalid. - // - internal string internalGetMonthName(int month, MonthNameStyles style, bool abbreviated) + /// + /// Return the month name using the specified MonthNameStyles in either abbreviated form + /// or full form. + /// + internal string InternalGetMonthName(int month, MonthNameStyles style, bool abbreviated) { - // - // Right now, style is mutual exclusive, but I make the style to be flag so that - // maybe we can combine flag if there is such a need. - // string[] monthNamesArray = null; switch (style) { case MonthNameStyles.Genitive: - monthNamesArray = internalGetGenitiveMonthNames(abbreviated); + monthNamesArray = InternalGetGenitiveMonthNames(abbreviated); break; case MonthNameStyles.LeapYear: - monthNamesArray = internalGetLeapYearMonthNames(/*abbreviated*/); + monthNamesArray = InternalGetLeapYearMonthNames(); break; default: - monthNamesArray = (abbreviated ? internalGetAbbreviatedMonthNames() : internalGetMonthNames()); + monthNamesArray = (abbreviated ? InternalGetAbbreviatedMonthNames() : InternalGetMonthNames()); break; } - // The month range is from 1 ~ this.m_monthNames.Length + + // The month range is from 1 ~ m_monthNames.Length // (actually is 13 right now for all cases) if ((month < 1) || (month > monthNamesArray.Length)) { throw new ArgumentOutOfRangeException( - nameof(month), SR.Format(SR.ArgumentOutOfRange_Range, - 1, monthNamesArray.Length)); + nameof(month), + month, + SR.Format(SR.ArgumentOutOfRange_Range, 1, monthNamesArray.Length)); } - return (monthNamesArray[month - 1]); + + return monthNamesArray[month - 1]; } - // - // internalGetGenitiveMonthNames - // - // Action: Retrieve the array which contains the month names in genitive form. - // If this culture does not use the gentive form, the normal month name is returned. - // Arguments: - // abbreviated When true, return abbreviated form. Otherwise, return a full form. - // - private string[] internalGetGenitiveMonthNames(bool abbreviated) + /// + /// Retrieve the array which contains the month names in genitive form. + /// If this culture does not use the gentive form, the normal month name is returned. + /// + private string[] InternalGetGenitiveMonthNames(bool abbreviated) { if (abbreviated) { - if (this.m_genitiveAbbreviatedMonthNames == null) + if (m_genitiveAbbreviatedMonthNames == null) { - this.m_genitiveAbbreviatedMonthNames = _cultureData.AbbreviatedGenitiveMonthNames(this.Calendar.ID); - Debug.Assert(this.m_genitiveAbbreviatedMonthNames.Length == 13, + m_genitiveAbbreviatedMonthNames = _cultureData.AbbreviatedGenitiveMonthNames(Calendar.ID); + Debug.Assert(m_genitiveAbbreviatedMonthNames.Length == 13, "[DateTimeFormatInfo.GetGenitiveMonthNames] Expected 13 abbreviated genitive month names in a year"); } - return (this.m_genitiveAbbreviatedMonthNames); + + return m_genitiveAbbreviatedMonthNames; } - if (this.genitiveMonthNames == null) + if (genitiveMonthNames == null) { - this.genitiveMonthNames = _cultureData.GenitiveMonthNames(this.Calendar.ID); - Debug.Assert(this.genitiveMonthNames.Length == 13, + genitiveMonthNames = _cultureData.GenitiveMonthNames(Calendar.ID); + Debug.Assert(genitiveMonthNames.Length == 13, "[DateTimeFormatInfo.GetGenitiveMonthNames] Expected 13 genitive month names in a year"); } - return (this.genitiveMonthNames); + + return genitiveMonthNames; } - // - // internalGetLeapYearMonthNames - // - // Actions: Retrieve the month names used in a leap year. - // If this culture does not have different month names in a leap year, the normal month name is returned. - // Arguments: None. (can use abbreviated later if needed) - // - internal string[] internalGetLeapYearMonthNames(/*bool abbreviated*/) + /// + /// Retrieve the month names used in a leap year. + /// If this culture does not have different month names in a leap year, + /// the normal month name is returned. + /// + internal string[] InternalGetLeapYearMonthNames() { - if (this.leapYearMonthNames == null) + if (leapYearMonthNames == null) { - Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.internalGetLeapYearMonthNames] Expected Calendar.ID > 0"); - this.leapYearMonthNames = _cultureData.LeapYearMonthNames(Calendar.ID); - Debug.Assert(this.leapYearMonthNames.Length == 13, - "[DateTimeFormatInfo.internalGetLeapYearMonthNames] Expepcted 13 leap year month names"); + Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.InternalGetLeapYearMonthNames] Expected Calendar.ID > 0"); + leapYearMonthNames = _cultureData.LeapYearMonthNames(Calendar.ID); + Debug.Assert(leapYearMonthNames.Length == 13, + "[DateTimeFormatInfo.InternalGetLeapYearMonthNames] Expepcted 13 leap year month names"); } + return (leapYearMonthNames); } - public string GetAbbreviatedDayName(DayOfWeek dayofweek) { - if ((int)dayofweek < 0 || (int)dayofweek > 6) + if (dayofweek < DayOfWeek.Sunday || dayofweek > DayOfWeek.Saturday) { throw new ArgumentOutOfRangeException( - nameof(dayofweek), SR.Format(SR.ArgumentOutOfRange_Range, - DayOfWeek.Sunday, DayOfWeek.Saturday)); + nameof(dayofweek), + dayofweek, + SR.Format(SR.ArgumentOutOfRange_Range, DayOfWeek.Sunday, DayOfWeek.Saturday)); } - // + // Don't call the public property AbbreviatedDayNames here since a clone is needed in that - // property, so it will be slower. Instead, use GetAbbreviatedDayOfWeekNames() directly. - // - return (internalGetAbbreviatedDayOfWeekNames()[(int)dayofweek]); + // property, so it will be slower. Instead, use GetAbbreviatedDayOfWeekNames() directly. + return InternalGetAbbreviatedDayOfWeekNames()[(int)dayofweek]; } - // Returns the super short day of week names for the specified day of week. + /// + /// Returns the super short day of week names for the specified day of week. + /// public string GetShortestDayName(DayOfWeek dayOfWeek) { - if ((int)dayOfWeek < 0 || (int)dayOfWeek > 6) + if (dayOfWeek < DayOfWeek.Sunday || dayOfWeek > DayOfWeek.Saturday) { throw new ArgumentOutOfRangeException( - nameof(dayOfWeek), SR.Format(SR.ArgumentOutOfRange_Range, - DayOfWeek.Sunday, DayOfWeek.Saturday)); + nameof(dayOfWeek), + dayOfWeek, + SR.Format(SR.ArgumentOutOfRange_Range, DayOfWeek.Sunday, DayOfWeek.Saturday)); } - // + // Don't call the public property SuperShortDayNames here since a clone is needed in that - // property, so it will be slower. Instead, use internalGetSuperShortDayNames() directly. - // - return (internalGetSuperShortDayNames()[(int)dayOfWeek]); + // property, so it will be slower. Instead, use internalGetSuperShortDayNames() directly. + return InternalGetSuperShortDayNames()[(int)dayOfWeek]; } - // Get all possible combination of inputs + /// + /// Get all possible combination of inputs + /// private static string[] GetCombinedPatterns(string[] patterns1, string[] patterns2, string connectString) { Debug.Assert(patterns1 != null); @@ -1530,7 +1454,7 @@ namespace System.Globalization } // Return the combinations - return (result); + return result; } public string[] GetAllDateTimePatterns() @@ -1555,10 +1479,10 @@ namespace System.Globalization switch (format) { case 'd': - result = this.AllShortDatePatterns; + result = AllShortDatePatterns; break; case 'D': - result = this.AllLongDatePatterns; + result = AllLongDatePatterns; break; case 'f': result = GetCombinedPatterns(AllLongDatePatterns, AllShortTimePatterns, " "); @@ -1589,36 +1513,36 @@ namespace System.Globalization result = new string[] { sortableDateTimePattern }; break; case 't': - result = this.AllShortTimePatterns; + result = AllShortTimePatterns; break; case 'T': - result = this.AllLongTimePatterns; + result = AllLongTimePatterns; break; case 'u': result = new string[] { UniversalSortableDateTimePattern }; break; case 'y': case 'Y': - result = this.AllYearMonthPatterns; + result = AllYearMonthPatterns; break; default: throw new ArgumentException(SR.Format(SR.Format_BadFormatSpecifier, format), nameof(format)); } - return (result); + return result; } - public string GetDayName(DayOfWeek dayofweek) { if ((int)dayofweek < 0 || (int)dayofweek > 6) { throw new ArgumentOutOfRangeException( - nameof(dayofweek), SR.Format(SR.ArgumentOutOfRange_Range, - DayOfWeek.Sunday, DayOfWeek.Saturday)); + nameof(dayofweek), + dayofweek, + SR.Format(SR.ArgumentOutOfRange_Range, DayOfWeek.Sunday, DayOfWeek.Saturday)); } // Use the internal one so that we don't clone the array unnecessarily - return (internalGetDayOfWeekNames()[(int)dayofweek]); + return InternalGetDayOfWeekNames()[(int)dayofweek]; } public string GetAbbreviatedMonthName(int month) @@ -1626,11 +1550,13 @@ namespace System.Globalization if (month < 1 || month > 13) { throw new ArgumentOutOfRangeException( - nameof(month), SR.Format(SR.ArgumentOutOfRange_Range, - 1, 13)); + nameof(month), + month, + SR.Format(SR.ArgumentOutOfRange_Range, 1, 13)); } + // Use the internal one so we don't clone the array unnecessarily - return (internalGetAbbreviatedMonthNames()[month - 1]); + return InternalGetAbbreviatedMonthNames()[month - 1]; } public string GetMonthName(int month) @@ -1638,20 +1564,24 @@ namespace System.Globalization if (month < 1 || month > 13) { throw new ArgumentOutOfRangeException( - nameof(month), SR.Format(SR.ArgumentOutOfRange_Range, - 1, 13)); + nameof(month), + month, + SR.Format(SR.ArgumentOutOfRange_Range, 1, 13)); } - // Use the internal one so we don't clone the array unnecessarily - return (internalGetMonthNames()[month - 1]); - } - // For our "patterns" arrays we have 2 variables, a string and a string[] - // - // The string[] contains the list of patterns, EXCEPT the default may not be included. - // The string contains the default pattern. - // When we initially construct our string[], we set the string to string[0] - // - // The resulting [] can get returned to the calling app, so clone it. + // Use the internal one so we don't clone the array unnecessarily + return InternalGetMonthNames()[month - 1]; + } + + /// + /// For our "patterns" arrays we have 2 variables, a string and a string[] + /// + /// The string[] contains the list of patterns, EXCEPT the default may not be included. + /// The string contains the default pattern. + /// When we initially construct our string[], we set the string to string[0] + /// + /// The resulting [] can get returned to the calling app, so clone it. + /// private static string[] GetMergedPatterns(string[] patterns, string defaultPattern) { Debug.Assert(patterns != null && patterns.Length > 0, @@ -1707,50 +1637,25 @@ namespace System.Globalization internal const string RoundtripFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK"; internal const string RoundtripDateTimeUnfixed = "yyyy'-'MM'-'ddTHH':'mm':'ss zzz"; - // Default string isn't necessarily in our string array, so get the - // merged patterns of both - private string[] AllYearMonthPatterns - { - get - { - return GetMergedPatterns(this.UnclonedYearMonthPatterns, this.YearMonthPattern); - } - } + /// + /// Default string isn't necessarily in our string array, so get the + /// merged patterns of both + /// + private string[] AllYearMonthPatterns => GetMergedPatterns(UnclonedYearMonthPatterns, YearMonthPattern); - private string[] AllShortDatePatterns - { - get - { - return GetMergedPatterns(this.UnclonedShortDatePatterns, this.ShortDatePattern); - } - } + private string[] AllShortDatePatterns => GetMergedPatterns(UnclonedShortDatePatterns, ShortDatePattern); - private string[] AllShortTimePatterns - { - get - { - return GetMergedPatterns(this.UnclonedShortTimePatterns, this.ShortTimePattern); - } - } + private string[] AllShortTimePatterns => GetMergedPatterns(UnclonedShortTimePatterns, ShortTimePattern); - private string[] AllLongDatePatterns - { - get - { - return GetMergedPatterns(this.UnclonedLongDatePatterns, this.LongDatePattern); - } - } + private string[] AllLongDatePatterns => GetMergedPatterns(UnclonedLongDatePatterns, LongDatePattern); - private string[] AllLongTimePatterns - { - get - { - return GetMergedPatterns(this.UnclonedLongTimePatterns, this.LongTimePattern); - } - } + private string[] AllLongTimePatterns => GetMergedPatterns(UnclonedLongTimePatterns, LongTimePattern); - // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy. - // This won't include default, call AllYearMonthPatterns + /// + /// Clone this string array if you want to return it to user. + /// Otherwise, you are returning a writable cache copy. + /// This won't include default, call AllYearMonthPatterns + /// private string[] UnclonedYearMonthPatterns { get @@ -1758,8 +1663,8 @@ namespace System.Globalization if (allYearMonthPatterns == null) { Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedYearMonthPatterns] Expected Calendar.ID > 0"); - this.allYearMonthPatterns = _cultureData.YearMonths(this.Calendar.ID); - Debug.Assert(this.allYearMonthPatterns.Length > 0, + allYearMonthPatterns = _cultureData.YearMonths(Calendar.ID); + Debug.Assert(allYearMonthPatterns.Length > 0, "[DateTimeFormatInfo.UnclonedYearMonthPatterns] Expected some year month patterns"); } @@ -1767,9 +1672,11 @@ namespace System.Globalization } } - - // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy. - // This won't include default, call AllShortDatePatterns + /// + /// Clone this string array if you want to return it to user. + /// Otherwise, you are returning a writable cache copy. + /// This won't include default, call AllShortDatePatterns + /// private string[] UnclonedShortDatePatterns { get @@ -1777,17 +1684,20 @@ namespace System.Globalization if (allShortDatePatterns == null) { Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedShortDatePatterns] Expected Calendar.ID > 0"); - this.allShortDatePatterns = _cultureData.ShortDates(this.Calendar.ID); - Debug.Assert(this.allShortDatePatterns.Length > 0, + allShortDatePatterns = _cultureData.ShortDates(Calendar.ID); + Debug.Assert(allShortDatePatterns.Length > 0, "[DateTimeFormatInfo.UnclonedShortDatePatterns] Expected some short date patterns"); } - return this.allShortDatePatterns; + return allShortDatePatterns; } } - // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy. - // This won't include default, call AllLongDatePatterns + /// + /// Clone this string array if you want to return it to user. + /// Otherwise, you are returning a writable cache copy. + /// This won't include default, call AllLongDatePatterns + /// private string[] UnclonedLongDatePatterns { get @@ -1795,46 +1705,52 @@ namespace System.Globalization if (allLongDatePatterns == null) { Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedLongDatePatterns] Expected Calendar.ID > 0"); - this.allLongDatePatterns = _cultureData.LongDates(this.Calendar.ID); - Debug.Assert(this.allLongDatePatterns.Length > 0, + allLongDatePatterns = _cultureData.LongDates(Calendar.ID); + Debug.Assert(allLongDatePatterns.Length > 0, "[DateTimeFormatInfo.UnclonedLongDatePatterns] Expected some long date patterns"); } - return this.allLongDatePatterns; + return allLongDatePatterns; } } - // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy. - // This won't include default, call AllShortTimePatterns + /// + /// Clone this string array if you want to return it to user. + /// Otherwise, you are returning a writable cache copy. + /// This won't include default, call AllShortTimePatterns + /// private string[] UnclonedShortTimePatterns { get { - if (this.allShortTimePatterns == null) + if (allShortTimePatterns == null) { - this.allShortTimePatterns = _cultureData.ShortTimes; - Debug.Assert(this.allShortTimePatterns.Length > 0, + allShortTimePatterns = _cultureData.ShortTimes; + Debug.Assert(allShortTimePatterns.Length > 0, "[DateTimeFormatInfo.UnclonedShortTimePatterns] Expected some short time patterns"); } - return this.allShortTimePatterns; + return allShortTimePatterns; } } - // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy. - // This won't include default, call AllLongTimePatterns + /// + /// Clone this string array if you want to return it to user. + /// Otherwise, you are returning a writable cache copy. + /// This won't include default, call AllLongTimePatterns + /// private string[] UnclonedLongTimePatterns { get { - if (this.allLongTimePatterns == null) + if (allLongTimePatterns == null) { - this.allLongTimePatterns = _cultureData.LongTimes; - Debug.Assert(this.allLongTimePatterns.Length > 0, + allLongTimePatterns = _cultureData.LongTimes; + Debug.Assert(allLongTimePatterns.Length > 0, "[DateTimeFormatInfo.UnclonedLongTimePatterns] Expected some long time patterns"); } - return this.allLongTimePatterns; + return allLongTimePatterns; } } @@ -1844,32 +1760,30 @@ namespace System.Globalization { throw new ArgumentNullException(nameof(dtfi)); } + if (dtfi.IsReadOnly) { - return (dtfi); + return dtfi; } + DateTimeFormatInfo newInfo = (DateTimeFormatInfo)(dtfi.MemberwiseClone()); // We can use the data member calendar in the setter, instead of the property Calendar, // since the cloned copy should have the same state as the original copy. newInfo.calendar = Calendar.ReadOnly(dtfi.Calendar); newInfo._isReadOnly = true; - return (newInfo); + return newInfo; } - public bool IsReadOnly - { - get - { - return (_isReadOnly); - } - } + public bool IsReadOnly => _isReadOnly; - // Return the native name for the calendar in DTFI.Calendar. The native name is referred to - // the culture used to create the DTFI. E.g. in the following example, the native language is Japanese. - // DateTimeFormatInfo dtfi = new CultureInfo("ja-JP", false).DateTimeFormat.Calendar = new JapaneseCalendar(); - // String nativeName = dtfi.NativeCalendarName; // Get the Japanese name for the Japanese calendar. - // DateTimeFormatInfo dtfi = new CultureInfo("ja-JP", false).DateTimeFormat.Calendar = new GregorianCalendar(GregorianCalendarTypes.Localized); - // String nativeName = dtfi.NativeCalendarName; // Get the Japanese name for the Gregorian calendar. + /// + /// Return the native name for the calendar in DTFI.Calendar. The native name is referred to + /// the culture used to create the DTFI. E.g. in the following example, the native language is Japanese. + /// DateTimeFormatInfo dtfi = new CultureInfo("ja-JP", false).DateTimeFormat.Calendar = new JapaneseCalendar(); + /// String nativeName = dtfi.NativeCalendarName; // Get the Japanese name for the Japanese calendar. + /// DateTimeFormatInfo dtfi = new CultureInfo("ja-JP", false).DateTimeFormat.Calendar = new GregorianCalendar(GregorianCalendarTypes.Localized); + /// String nativeName = dtfi.NativeCalendarName; // Get the Japanese name for the Gregorian calendar. + /// public string NativeCalendarName { get @@ -1878,31 +1792,32 @@ namespace System.Globalization } } - // - // Used by custom cultures and others to set the list of available formats. Note that none of them are - // explicitly used unless someone calls GetAllDateTimePatterns and subsequently uses one of the items - // from the list. - // - // Most of the format characters that can be used in GetAllDateTimePatterns are - // not really needed since they are one of the following: - // - // r/R/s/u locale-independent constants -- cannot be changed! - // m/M/y/Y fields with a single string in them -- that can be set through props directly - // f/F/g/G/U derived fields based on combinations of various of the below formats - // - // NOTE: No special validation is done here beyond what is done when the actual respective fields - // are used (what would be the point of disallowing here what we allow in the appropriate property?) - // - // WARNING: If more validation is ever done in one place, it should be done in the other. - // + /// + /// Used by custom cultures and others to set the list of available formats. Note that none of them are + /// explicitly used unless someone calls GetAllDateTimePatterns and subsequently uses one of the items + /// from the list. + /// + /// Most of the format characters that can be used in GetAllDateTimePatterns are + /// not really needed since they are one of the following: + /// + /// r/R/s/u locale-independent constants -- cannot be changed! + /// m/M/y/Y fields with a single string in them -- that can be set through props directly + /// f/F/g/G/U derived fields based on combinations of various of the below formats + /// + /// NOTE: No special validation is done here beyond what is done when the actual respective fields + /// are used (what would be the point of disallowing here what we allow in the appropriate property?) + /// + /// WARNING: If more validation is ever done in one place, it should be done in the other. + /// public void SetAllDateTimePatterns(string[] patterns, char format) { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - + } if (patterns == null) { - throw new ArgumentNullException(nameof(patterns), SR.ArgumentNull_Array); + throw new ArgumentNullException(nameof(patterns)); } if (patterns.Length == 0) @@ -1910,7 +1825,6 @@ namespace System.Globalization throw new ArgumentException(SR.Arg_ArrayZeroError, nameof(patterns)); } - for (int i = 0; i < patterns.Length; i++) { if (patterns[i] == null) @@ -1958,59 +1872,53 @@ namespace System.Globalization public string[] AbbreviatedMonthGenitiveNames { - get - { - return ((string[])internalGetGenitiveMonthNames(true).Clone()); - } - + get => (string[])InternalGetGenitiveMonthNames(true).Clone(); set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_Array); + throw new ArgumentNullException(nameof(value)); } if (value.Length != 13) { throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), nameof(value)); } + CheckNullValue(value, value.Length - 1); ClearTokenHashTable(); - this.m_genitiveAbbreviatedMonthNames = value; + m_genitiveAbbreviatedMonthNames = value; } } public string[] MonthGenitiveNames { - get - { - return ((string[])internalGetGenitiveMonthNames(false).Clone()); - } - + get => (string[])InternalGetGenitiveMonthNames(false).Clone(); set { if (IsReadOnly) + { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } if (value == null) { - throw new ArgumentNullException(nameof(value), - SR.ArgumentNull_Array); + throw new ArgumentNullException(nameof(value)); } if (value.Length != 13) { throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), nameof(value)); } + CheckNullValue(value, value.Length - 1); genitiveMonthNames = value; ClearTokenHashTable(); } } - // // Decimal separator used by positive TimeSpan pattern - // private string _decimalSeparator; internal string DecimalSeparator { @@ -2027,9 +1935,7 @@ namespace System.Globalization } } - // // Positive TimeSpan Pattern - // private string _fullTimeSpanPositivePattern; internal string FullTimeSpanPositivePattern { @@ -2043,9 +1949,7 @@ namespace System.Globalization } } - // // Negative TimeSpan Pattern - // private string _fullTimeSpanNegativePattern; internal string FullTimeSpanNegativePattern { @@ -2057,9 +1961,7 @@ namespace System.Globalization } } - // // Get suitable CompareInfo from current DTFI object. - // internal CompareInfo CompareInfo { get @@ -2068,14 +1970,13 @@ namespace System.Globalization { // We use the regular GetCompareInfo here to make sure the created CompareInfo object is stored in the // CompareInfo cache. otherwise we would just create CompareInfo using _cultureData. - _compareInfo = CompareInfo.GetCompareInfo(_cultureData.SCOMPAREINFO); + _compareInfo = CompareInfo.GetCompareInfo(_cultureData.SortName); } return _compareInfo; } } - internal const DateTimeStyles InvalidDateTimeStyles = ~(DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.AllowInnerWhite | DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeLocal @@ -2098,20 +1999,22 @@ namespace System.Globalization } } - // - // Actions: Return the internal flag used in formatting and parsing. - // The flag can be used to indicate things like if genitive forms is used in this DTFi, or if leap year gets different month names. - // + /// + /// Return the internal flag used in formatting and parsing. + /// The flag can be used to indicate things like if genitive forms is used in + /// this DTFi, or if leap year gets different month names. + /// internal DateTimeFormatFlags FormatFlags => formatFlags != DateTimeFormatFlags.NotInitialized ? formatFlags : InitializeFormatFlags(); + [MethodImpl(MethodImplOptions.NoInlining)] private DateTimeFormatFlags InitializeFormatFlags() { // Build the format flags from the data in this DTFI formatFlags = (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagGenitiveMonth( - MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true)) | + MonthNames, InternalGetGenitiveMonthNames(false), AbbreviatedMonthNames, InternalGetGenitiveMonthNames(true)) | (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInMonthNames( - MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true)) | + MonthNames, InternalGetGenitiveMonthNames(false), AbbreviatedMonthNames, InternalGetGenitiveMonthNames(true)) | (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInDayNames(DayNames, AbbreviatedDayNames) | (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseHebrewCalendar((int)Calendar.ID); return formatFlags; @@ -2139,20 +2042,21 @@ namespace System.Globalization } } - // Returns whether the YearMonthAdjustment function has any fix-up work to do for this culture/calendar. + /// + /// Returns whether the YearMonthAdjustment function has any fix-up work to do for this culture/calendar. + /// internal bool HasYearMonthAdjustment { - get - { - return ((FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0); - } + get => (FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0; } - // This is a callback that the parser can make back into the DTFI to let it fiddle with special - // cases associated with that culture or calendar. Currently this only has special cases for - // the Hebrew calendar, but this could be extended to other cultures. - // - // The return value is whether the year and month are actually valid for this calendar. + /// + /// This is a callback that the parser can make back into the DTFI to let it fiddle with special + /// cases associated with that culture or calendar. Currently this only has special cases for + /// the Hebrew calendar, but this could be extended to other cultures. + /// + /// The return value is whether the year and month are actually valid for this calendar. + /// internal bool YearMonthAdjustment(ref int year, ref int month, bool parsedMonthName) { if ((FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0) @@ -2193,9 +2097,7 @@ namespace System.Globalization return true; } - // // DateTimeFormatInfo tokenizer. This is used by DateTime.Parse() to break input string into tokens. - // private TokenHashValue[] _dtfiTokenHash; private const int TOKEN_HASH_SIZE = 199; @@ -2204,15 +2106,11 @@ namespace System.Globalization private const string invariantDateSeparator = "/"; private const string invariantTimeSeparator = ":"; - // // Common Ignorable Symbols - // internal const string IgnorablePeriod = "."; internal const string IgnorableComma = ","; - // // Year/Month/Day suffixes - // internal const string CJKYearSuff = "\u5e74"; internal const string CJKMonthSuff = "\u6708"; internal const string CJKDaySuff = "\u65e5"; @@ -2245,12 +2143,12 @@ namespace System.Globalization private static volatile DateTimeFormatInfo s_jajpDTFI; private static volatile DateTimeFormatInfo s_zhtwDTFI; - // - // Create a Japanese DTFI which uses JapaneseCalendar. This is used to parse - // date string with Japanese era name correctly even when the supplied DTFI - // does not use Japanese calendar. - // The created instance is stored in global s_jajpDTFI. - // + /// + /// Create a Japanese DTFI which uses JapaneseCalendar. This is used to parse + /// date string with Japanese era name correctly even when the supplied DTFI + /// does not use Japanese calendar. + /// The created instance is stored in global s_jajpDTFI. + /// internal static DateTimeFormatInfo GetJapaneseCalendarDTFI() { DateTimeFormatInfo temp = s_jajpDTFI; @@ -2260,13 +2158,15 @@ namespace System.Globalization temp.Calendar = JapaneseCalendar.GetDefaultInstance(); s_jajpDTFI = temp; } - return (temp); + return temp; } - // Create a Taiwan DTFI which uses TaiwanCalendar. This is used to parse - // date string with era name correctly even when the supplied DTFI - // does not use Taiwan calendar. - // The created instance is stored in global s_zhtwDTFI. + /// + /// Create a Taiwan DTFI which uses TaiwanCalendar. This is used to parse + /// date string with era name correctly even when the supplied DTFI + /// does not use Taiwan calendar. + /// The created instance is stored in global s_zhtwDTFI. + /// internal static DateTimeFormatInfo GetTaiwanCalendarDTFI() { DateTimeFormatInfo temp = s_zhtwDTFI; @@ -2276,11 +2176,12 @@ namespace System.Globalization temp.Calendar = TaiwanCalendar.GetDefaultInstance(); s_zhtwDTFI = temp; } - return (temp); + return temp; } - - // DTFI properties should call this when the setter are called. + /// + /// DTFI properties should call this when the setter are called. + /// private void ClearTokenHashTable() { _dtfiTokenHash = null; @@ -2296,7 +2197,7 @@ namespace System.Globalization bool koreanLanguage = LanguageName.Equals(KoreanLangName); - string sep = this.TimeSeparator.Trim(); + string sep = TimeSeparator.Trim(); if (IgnorableComma != sep) InsertHash(temp, IgnorableComma, TokenType.IgnorableSymbol, 0); if (IgnorablePeriod != sep) InsertHash(temp, IgnorablePeriod, TokenType.IgnorableSymbol, 0); @@ -2308,18 +2209,17 @@ namespace System.Globalization // DateTime.Parse behavior. For instance, the DateTimeFormatInfo.Tokenize() method might return SEP_DateOrOffset for KoreanHourSuff // instead of SEP_HourSuff. // - InsertHash(temp, this.TimeSeparator, TokenType.SEP_Time, 0); + InsertHash(temp, TimeSeparator, TokenType.SEP_Time, 0); } - InsertHash(temp, this.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0); - InsertHash(temp, this.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1); + InsertHash(temp, AMDesignator, TokenType.SEP_Am | TokenType.Am, 0); + InsertHash(temp, PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1); - // TODO: This ignores similar custom cultures if (LanguageName.Equals("sq")) { // Albanian allows time formats like "12:00.PD" - InsertHash(temp, IgnorablePeriod + this.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0); - InsertHash(temp, IgnorablePeriod + this.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1); + InsertHash(temp, IgnorablePeriod + AMDesignator, TokenType.SEP_Am | TokenType.Am, 0); + InsertHash(temp, IgnorablePeriod + PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1); } // CJK suffix @@ -2395,7 +2295,7 @@ namespace System.Globalization case DateTimeFormatInfoScanner.IgnorableSymbolChar: string symbol = dateWords[i].Substring(1); InsertHash(temp, symbol, TokenType.IgnorableSymbol, 0); - if (this.DateSeparator.Trim(null).Equals(symbol)) + if (DateSeparator.Trim(null).Equals(symbol)) { // The date separator is the same as the ignorable symbol. useDateSepAsIgnorableSymbol = true; @@ -2417,7 +2317,7 @@ namespace System.Globalization if (!useDateSepAsIgnorableSymbol) { // Use the normal date separator. - InsertHash(temp, this.DateSeparator, TokenType.SEP_Date, 0); + InsertHash(temp, DateSeparator, TokenType.SEP_Date, 0); } // Add the regular month names. AddMonthNames(temp); @@ -2434,7 +2334,7 @@ namespace System.Globalization for (int i = 1; i <= 13; i++) { string str; - str = internalGetMonthName(i, MonthNameStyles.Genitive, false); + str = InternalGetMonthName(i, MonthNameStyles.Genitive, false); InsertHash(temp, str, TokenType.MonthToken, i); } } @@ -2444,7 +2344,7 @@ namespace System.Globalization for (int i = 1; i <= 13; i++) { string str; - str = internalGetMonthName(i, MonthNameStyles.LeapYear, false); + str = InternalGetMonthName(i, MonthNameStyles.LeapYear, false); InsertHash(temp, str, TokenType.MonthToken, i); } } @@ -2467,7 +2367,6 @@ namespace System.Globalization InsertHash(temp, GetAbbreviatedEraName(i), TokenType.EraToken, i); } - // TODO: This ignores other cultures that might want to do something similar if (LanguageName.Equals(JapaneseLangName)) { // Japanese allows day of week forms like: "(Tue)" @@ -2476,7 +2375,7 @@ namespace System.Globalization string specialDayOfWeek = "(" + GetAbbreviatedDayName((DayOfWeek)i) + ")"; InsertHash(temp, specialDayOfWeek, TokenType.DayOfWeekToken, i); } - if (this.Calendar.GetType() != typeof(JapaneseCalendar)) + if (Calendar.GetType() != typeof(JapaneseCalendar)) { // Special case for Japanese. If this is a Japanese DTFI, and the calendar is not Japanese calendar, // we will check Japanese Era name as well when the calendar is Gregorian. @@ -2573,19 +2472,15 @@ namespace System.Globalization } } - //////////////////////////////////////////////////////////////////////// - // - // Actions: - // Try to parse the current word to see if it is a Hebrew number. - // Tokens will be updated accordingly. - // This is called by the Lexer of DateTime.Parse(). - // - // Unlike most of the functions in this class, the return value indicates - // whether or not it started to parse. The badFormat parameter indicates - // if parsing began, but the format was bad. - // - //////////////////////////////////////////////////////////////////////// - + /// + /// Try to parse the current word to see if it is a Hebrew number. + /// Tokens will be updated accordingly. + /// This is called by the Lexer of DateTime.Parse(). + /// + /// Unlike most of the functions in this class, the return value indicates + /// whether or not it started to parse. The badFormat parameter indicates + /// if parsing began, but the format was bad. + /// private static bool TryParseHebrewNumber( ref __DTString str, out bool badFormat, @@ -2599,7 +2494,7 @@ namespace System.Globalization { // If the current character is not a Hebrew digit, just return false. // There is no chance that we can parse a valid Hebrew number from here. - return (false); + return false; } // The current character is a Hebrew digit. Try to parse this word as a Hebrew number. HebrewNumberParsingContext context = new HebrewNumberParsingContext(0); @@ -2613,7 +2508,7 @@ namespace System.Globalization case HebrewNumberParsingState.InvalidHebrewNumber: // Not a valid Hebrew number. case HebrewNumberParsingState.NotHebrewDigit: // The current character is not a Hebrew digit character. // Break out so that we don't continue to try parse this as a Hebrew number. - return (false); + return false; } } while (i < str.Value.Length && (state != HebrewNumberParsingState.FoundEndOfHebrewNumber)); @@ -2624,7 +2519,7 @@ namespace System.Globalization if (state != HebrewNumberParsingState.FoundEndOfHebrewNumber) { // We reach end of the string but we can't find a terminal state in parsing Hebrew number. - return (false); + return false; } // We have found a valid Hebrew number. Update the index. @@ -2633,7 +2528,7 @@ namespace System.Globalization // Get the final Hebrew number value from the HebrewNumberParsingContext. number = context.result; - return (true); + return true; } private static bool IsHebrewChar(char ch) @@ -2673,7 +2568,7 @@ namespace System.Globalization bool isLetter = char.IsLetter(ch); if (isLetter) { - ch = this.Culture.TextInfo.ToLower(ch); + ch = Culture.TextInfo.ToLower(ch); if (IsHebrewChar(ch) && TokenMask == TokenType.RegularTokenMask) { bool badFormat; @@ -2739,7 +2634,7 @@ namespace System.Globalization tokenType = value.tokenType & TokenMask; tokenValue = value.tokenValue; str.Advance(value.tokenString.Length); - return (true); + return true; } else if ((value.tokenType == TokenType.MonthToken && HasSpacesInMonthNames) || (value.tokenType == TokenType.DayOfWeekToken && HasSpacesInDayNames)) @@ -2751,7 +2646,7 @@ namespace System.Globalization tokenType = value.tokenType & TokenMask; tokenValue = value.tokenValue; str.Advance(matchStrLen); - return (true); + return true; } } } @@ -2760,7 +2655,7 @@ namespace System.Globalization if (hashcode >= TOKEN_HASH_SIZE) hashcode -= TOKEN_HASH_SIZE; } while (i < TOKEN_HASH_SIZE); - return (false); + return false; } private void InsertAtCurrentHashNode(TokenHashValue[] hashTable, string str, char ch, TokenType tokenType, int tokenValue, int pos, int hashcode, int hashProbe) @@ -2768,7 +2663,6 @@ namespace System.Globalization // Remember the current slot. TokenHashValue previousNode = hashTable[hashcode]; - //// Console.WriteLine(" Insert Key: {0} in {1}", str, slotToInsert); // Insert the new node into the current slot. hashTable[hashcode] = new TokenHashValue(str, tokenType, tokenValue); ; @@ -2779,13 +2673,12 @@ namespace System.Globalization // Remember this slot TokenHashValue temp = hashTable[hashcode]; - if (temp != null && this.Culture.TextInfo.ToLower(temp.tokenString[0]) != ch) + if (temp != null && Culture.TextInfo.ToLower(temp.tokenString[0]) != ch) { continue; } // Put the previous slot into this slot. hashTable[hashcode] = previousNode; - //// Console.WriteLine(" Move {0} to slot {1}", previousNode.tokenString, hashcode); if (temp == null) { // Done @@ -2812,9 +2705,11 @@ namespace System.Globalization str = str.Trim(null); // Trim white space characters. // Could have space for separators if (str.Length == 0) + { return; + } } - char ch = this.Culture.TextInfo.ToLower(str[0]); + char ch = Culture.TextInfo.ToLower(str[0]); int hashcode = ch % TOKEN_HASH_SIZE; int hashProbe = 1 + ch % SECOND_PRIME; do @@ -2822,7 +2717,6 @@ namespace System.Globalization value = hashTable[hashcode]; if (value == null) { - //// Console.WriteLine(" Put Key: {0} in {1}", str, hashcode); hashTable[hashcode] = new TokenHashValue(str, tokenType, tokenValue); return; } @@ -2833,7 +2727,7 @@ namespace System.Globalization { // If there are two tokens with the same prefix, we have to make sure that the longer token should be at the front of // the shorter ones. - if (this.CompareStringIgnoreCaseOptimized(str, 0, value.tokenString.Length, value.tokenString, 0, value.tokenString.Length)) + if (CompareStringIgnoreCaseOptimized(str, 0, value.tokenString.Length, value.tokenString, 0, value.tokenString.Length)) { if (str.Length > value.tokenString.Length) { @@ -2848,19 +2742,13 @@ namespace System.Globalization // If we have the same regular token or separator token in the hash already, do NOT update the hash. // Therefore, the order of inserting token is significant here regarding what tokenType will be kept in the hash. - - // // Check the current value of RegularToken (stored in the lower 8-bit of tokenType) , and insert the tokenType into the hash ONLY when we don't have a RegularToken yet. // Also check the current value of SeparatorToken (stored in the upper 8-bit of token), and insert the tokenType into the hash ONLY when we don't have the SeparatorToken yet. - // int nTokenType = (int)tokenType; int nCurrentTokenTypeInHash = (int)value.tokenType; - // // The folowing is the fix for the issue of throwing FormatException when "mar" is passed in string of the short date format dd/MMM/yyyy for es-MX - // - if (((nCurrentTokenTypeInHash & (int)TokenType.RegularTokenMask) == 0) && ((nTokenType & (int)TokenType.RegularTokenMask) != 0) || ((nCurrentTokenTypeInHash & (int)TokenType.SeparatorTokenMask) == 0) && ((nTokenType & (int)TokenType.SeparatorTokenMask) != 0)) { @@ -2876,7 +2764,6 @@ namespace System.Globalization } } } - //// Console.WriteLine(" COLLISION. Old Key: {0}, New Key: {1}", hashTable[hashcode].tokenString, str); i++; hashcode += hashProbe; if (hashcode >= TOKEN_HASH_SIZE) hashcode -= TOKEN_HASH_SIZE; @@ -2892,11 +2779,9 @@ namespace System.Globalization return true; } - return (this.Culture.CompareInfo.Compare(string1, offset1, length1, string2, offset2, length2, CompareOptions.IgnoreCase) == 0); + return Culture.CompareInfo.Compare(string1, offset1, length1, string2, offset2, length2, CompareOptions.IgnoreCase) == 0; } - // class DateTimeFormatInfo - internal class TokenHashValue { internal string tokenString; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs index 9c0913e..bc0193d 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs @@ -3343,7 +3343,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, // Search leap year form. if ((dtfi.FormatFlags & DateTimeFormatFlags.UseLeapYearMonth) != 0) { - int tempResult = str.MatchLongestWords(dtfi.internalGetLeapYearMonthNames(), ref maxMatchStrLen); + int tempResult = str.MatchLongestWords(dtfi.InternalGetLeapYearMonthNames(), ref maxMatchStrLen); // We found a longer match in the leap year month name. Use this as the result. // The result from MatchLongestWords is 0 ~ length of word array. // So we increment the result by one to become the month value. @@ -3414,7 +3414,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, // Search leap year form. if ((dtfi.FormatFlags & DateTimeFormatFlags.UseLeapYearMonth) != 0) { - int tempResult = str.MatchLongestWords(dtfi.internalGetLeapYearMonthNames(), ref maxMatchStrLen); + int tempResult = str.MatchLongestWords(dtfi.InternalGetLeapYearMonthNames(), ref maxMatchStrLen); // We found a longer match in the leap year month name. Use this as the result. // The result from MatchLongestWords is 0 ~ length of word array. // So we increment the result by one to become the month value. diff --git a/src/System.Private.CoreLib/shared/System/Globalization/NumberFormatInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/NumberFormatInfo.cs index 0d2db23..09030b9 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/NumberFormatInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/NumberFormatInfo.cs @@ -2,79 +2,74 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. - namespace System.Globalization { - // - // Property Default Description - // PositiveSign '+' Character used to indicate positive values. - // NegativeSign '-' Character used to indicate negative values. - // NumberDecimalSeparator '.' The character used as the decimal separator. - // NumberGroupSeparator ',' The character used to separate groups of - // digits to the left of the decimal point. - // NumberDecimalDigits 2 The default number of decimal places. - // NumberGroupSizes 3 The number of digits in each group to the - // left of the decimal point. - // NaNSymbol "NaN" The string used to represent NaN values. - // PositiveInfinitySymbol"Infinity" The string used to represent positive - // infinities. - // NegativeInfinitySymbol"-Infinity" The string used to represent negative - // infinities. - // - // - // - // Property Default Description - // CurrencyDecimalSeparator '.' The character used as the decimal - // separator. - // CurrencyGroupSeparator ',' The character used to separate groups - // of digits to the left of the decimal - // point. - // CurrencyDecimalDigits 2 The default number of decimal places. - // CurrencyGroupSizes 3 The number of digits in each group to - // the left of the decimal point. - // CurrencyPositivePattern 0 The format of positive values. - // CurrencyNegativePattern 0 The format of negative values. - // CurrencySymbol "$" String used as local monetary symbol. - // - + /// + /// Property Default Description + /// PositiveSign '+' Character used to indicate positive values. + /// NegativeSign '-' Character used to indicate negative values. + /// NumberDecimalSeparator '.' The character used as the decimal separator. + /// NumberGroupSeparator ',' The character used to separate groups of + /// digits to the left of the decimal point. + /// NumberDecimalDigits 2 The default number of decimal places. + /// NumberGroupSizes 3 The number of digits in each group to the + /// left of the decimal point. + /// NaNSymbol "NaN" The string used to represent NaN values. + /// PositiveInfinitySymbol"Infinity" The string used to represent positive + /// infinities. + /// NegativeInfinitySymbol"-Infinity" The string used to represent negative + /// infinities. + /// + /// Property Default Description + /// CurrencyDecimalSeparator '.' The character used as the decimal + /// separator. + /// CurrencyGroupSeparator ',' The character used to separate groups + /// of digits to the left of the decimal + /// point. + /// CurrencyDecimalDigits 2 The default number of decimal places. + /// CurrencyGroupSizes 3 The number of digits in each group to + /// the left of the decimal point. + /// CurrencyPositivePattern 0 The format of positive values. + /// CurrencyNegativePattern 0 The format of negative values. + /// CurrencySymbol "$" String used as local monetary symbol. + /// public sealed class NumberFormatInfo : IFormatProvider, ICloneable { - // invariantInfo is constant irrespective of your current culture. private static volatile NumberFormatInfo s_invariantInfo; - internal int[] numberGroupSizes = new int[] { 3 }; - internal int[] currencyGroupSizes = new int[] { 3 }; - internal int[] percentGroupSizes = new int[] { 3 }; - internal string positiveSign = "+"; - internal string negativeSign = "-"; - internal string numberDecimalSeparator = "."; - internal string numberGroupSeparator = ","; - internal string currencyGroupSeparator = ","; - internal string currencyDecimalSeparator = "."; - internal string currencySymbol = "\x00a4"; // U+00a4 is the symbol for International Monetary Fund. - internal string nanSymbol = "NaN"; - internal string positiveInfinitySymbol = "Infinity"; - internal string negativeInfinitySymbol = "-Infinity"; - internal string percentDecimalSeparator = "."; - internal string percentGroupSeparator = ","; - internal string percentSymbol = "%"; - internal string perMilleSymbol = "\u2030"; - - - internal string[] nativeDigits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; - - internal int numberDecimalDigits = 2; - internal int currencyDecimalDigits = 2; - internal int currencyPositivePattern = 0; - internal int currencyNegativePattern = 0; - internal int numberNegativePattern = 1; - internal int percentPositivePattern = 0; - internal int percentNegativePattern = 0; - internal int percentDecimalDigits = 2; - - internal int digitSubstitution = (int)DigitShapes.None; - - internal bool isReadOnly = false; + internal int[] _numberGroupSizes = new int[] { 3 }; + internal int[] _currencyGroupSizes = new int[] { 3 }; + internal int[] _percentGroupSizes = new int[] { 3 }; + internal string _positiveSign = "+"; + internal string _negativeSign = "-"; + internal string _numberDecimalSeparator = "."; + internal string _numberGroupSeparator = ","; + internal string _currencyGroupSeparator = ","; + internal string _currencyDecimalSeparator = "."; + internal string _currencySymbol = "\x00a4"; // U+00a4 is the symbol for International Monetary Fund. + internal string _nanSymbol = "NaN"; + internal string _positiveInfinitySymbol = "Infinity"; + internal string _negativeInfinitySymbol = "-Infinity"; + internal string _percentDecimalSeparator = "."; + internal string _percentGroupSeparator = ","; + internal string _percentSymbol = "%"; + internal string _perMilleSymbol = "\u2030"; + + + internal string[] _nativeDigits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + + internal int _numberDecimalDigits = 2; + internal int _currencyDecimalDigits = 2; + internal int _currencyPositivePattern = 0; + internal int _currencyNegativePattern = 0; + internal int _numberNegativePattern = 1; + internal int _percentPositivePattern = 0; + internal int _percentNegativePattern = 0; + internal int _percentDecimalDigits = 2; + + internal int _digitSubstitution = (int)DigitShapes.None; + + internal bool _isReadOnly = false; private bool _hasInvariantNumberSigns = true; @@ -86,13 +81,12 @@ namespace System.Globalization { if (decSep == null) { - throw new ArgumentNullException(propertyName, - SR.ArgumentNull_String); + throw new ArgumentNullException(propertyName); } if (decSep.Length == 0) { - throw new ArgumentException(SR.Argument_EmptyDecString); + throw new ArgumentException(SR.Argument_EmptyDecString, propertyName); } } @@ -100,8 +94,7 @@ namespace System.Globalization { if (groupSep == null) { - throw new ArgumentNullException(propertyName, - SR.ArgumentNull_String); + throw new ArgumentNullException(propertyName); } } @@ -167,7 +160,7 @@ namespace System.Globalization private void UpdateHasInvariantNumberSigns() { - _hasInvariantNumberSigns = positiveSign == "+" && negativeSign == "-"; + _hasInvariantNumberSigns = _positiveSign == "+" && _negativeSign == "-"; } internal NumberFormatInfo(CultureData cultureData) @@ -184,17 +177,17 @@ namespace System.Globalization private void VerifyWritable() { - if (isReadOnly) + if (_isReadOnly) { throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); } } - // Returns a default NumberFormatInfo that will be universally - // supported and constant irrespective of the current culture. - // Used by FromString methods. - // - + /// + /// Returns a default NumberFormatInfo that will be universally + /// supported and constant irrespective of the current culture. + /// Used by FromString methods. + /// public static NumberFormatInfo InvariantInfo { get @@ -205,7 +198,7 @@ namespace System.Globalization // be thrown out of a .cctor stack that will need this. s_invariantInfo = new NumberFormatInfo { - isReadOnly = true + _isReadOnly = true }; } return s_invariantInfo; @@ -236,57 +229,47 @@ namespace System.Globalization public object Clone() { NumberFormatInfo n = (NumberFormatInfo)MemberwiseClone(); - n.isReadOnly = false; + n._isReadOnly = false; return n; } public int CurrencyDecimalDigits { - get { return currencyDecimalDigits; } + get => _currencyDecimalDigits; set { if (value < 0 || value > 99) { throw new ArgumentOutOfRangeException( - nameof(CurrencyDecimalDigits), - SR.Format( - SR.ArgumentOutOfRange_Range, - 0, - 99)); + nameof(value), + value, + SR.Format(SR.ArgumentOutOfRange_Range, 0, 99)); } + VerifyWritable(); - currencyDecimalDigits = value; + _currencyDecimalDigits = value; } } - public string CurrencyDecimalSeparator { - get { return currencyDecimalSeparator; } + get => _currencyDecimalSeparator; set { VerifyWritable(); - VerifyDecimalSeparator(value, nameof(CurrencyDecimalSeparator)); - currencyDecimalSeparator = value; + VerifyDecimalSeparator(value, nameof(value)); + _currencyDecimalSeparator = value; } } + public bool IsReadOnly => _isReadOnly; - public bool IsReadOnly - { - get - { - return isReadOnly; - } - } - - // - // Check the values of the groupSize array. - // - // Every element in the groupSize array should be between 1 and 9 - // excpet the last element could be zero. - // + /// + /// Check the values of the groupSize array. + /// Every element in the groupSize array should be between 1 and 9 + /// except the last element could be zero. + /// internal static void CheckGroupSize(string propName, int[] groupSize) { for (int i = 0; i < groupSize.Length; i++) @@ -294,7 +277,10 @@ namespace System.Globalization if (groupSize[i] < 1) { if (i == groupSize.Length - 1 && groupSize[i] == 0) + { return; + } + throw new ArgumentException(SR.Argument_InvalidGroupSize, propName); } else if (groupSize[i] > 9) @@ -307,96 +293,89 @@ namespace System.Globalization public int[] CurrencyGroupSizes { - get - { - return ((int[])currencyGroupSizes.Clone()); - } + get => ((int[])_currencyGroupSizes.Clone()); set { if (value == null) { - throw new ArgumentNullException(nameof(CurrencyGroupSizes)); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); int[] inputSizes = (int[])value.Clone(); - CheckGroupSize(nameof(CurrencyGroupSizes), inputSizes); - currencyGroupSizes = inputSizes; + CheckGroupSize(nameof(value), inputSizes); + _currencyGroupSizes = inputSizes; } } - - public int[] NumberGroupSizes { - get - { - return ((int[])numberGroupSizes.Clone()); - } + get => ((int[])_numberGroupSizes.Clone()); set { if (value == null) { - throw new ArgumentNullException(nameof(NumberGroupSizes)); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); int[] inputSizes = (int[])value.Clone(); - CheckGroupSize(nameof(NumberGroupSizes), inputSizes); - numberGroupSizes = inputSizes; + CheckGroupSize(nameof(value), inputSizes); + _numberGroupSizes = inputSizes; } } public int[] PercentGroupSizes { - get - { - return ((int[])percentGroupSizes.Clone()); - } + get => ((int[])_percentGroupSizes.Clone()); set { if (value == null) { - throw new ArgumentNullException(nameof(PercentGroupSizes)); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); int[] inputSizes = (int[])value.Clone(); - CheckGroupSize(nameof(PercentGroupSizes), inputSizes); - percentGroupSizes = inputSizes; + CheckGroupSize(nameof(value), inputSizes); + _percentGroupSizes = inputSizes; } } public string CurrencyGroupSeparator { - get { return currencyGroupSeparator; } + get => _currencyGroupSeparator; set { VerifyWritable(); - VerifyGroupSeparator(value, nameof(CurrencyGroupSeparator)); - currencyGroupSeparator = value; + VerifyGroupSeparator(value, nameof(value)); + _currencyGroupSeparator = value; } } public string CurrencySymbol { - get { return currencySymbol; } + get => _currencySymbol; set { if (value == null) { - throw new ArgumentNullException(nameof(CurrencySymbol), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); - currencySymbol = value; + _currencySymbol = value; } } - // Returns the current culture's NumberFormatInfo. Used by Parse methods. - // + /// + /// Returns the current culture's NumberFormatInfo. Used by Parse methods. + /// public static NumberFormatInfo CurrentInfo { @@ -415,349 +394,309 @@ namespace System.Globalization } } - public string NaNSymbol { - get - { - return nanSymbol; - } + get => _nanSymbol; set { if (value == null) { - throw new ArgumentNullException(nameof(NaNSymbol), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); - nanSymbol = value; + _nanSymbol = value; } } - - public int CurrencyNegativePattern { - get { return currencyNegativePattern; } + get => _currencyNegativePattern; set { if (value < 0 || value > 15) { throw new ArgumentOutOfRangeException( - nameof(CurrencyNegativePattern), - SR.Format( - SR.ArgumentOutOfRange_Range, - 0, - 15)); + nameof(value), + value, + SR.Format(SR.ArgumentOutOfRange_Range, 0, 15)); } + VerifyWritable(); - currencyNegativePattern = value; + _currencyNegativePattern = value; } } - public int NumberNegativePattern { - get { return numberNegativePattern; } + get => _numberNegativePattern; set { - // // NOTENOTE: the range of value should correspond to negNumberFormats[] in vm\COMNumber.cpp. - // if (value < 0 || value > 4) { throw new ArgumentOutOfRangeException( - nameof(NumberNegativePattern), - SR.Format( - SR.ArgumentOutOfRange_Range, - 0, - 4)); + nameof(value), + value, + SR.Format(SR.ArgumentOutOfRange_Range, 0, 4)); } + VerifyWritable(); - numberNegativePattern = value; + _numberNegativePattern = value; } } - public int PercentPositivePattern { - get { return percentPositivePattern; } + get => _percentPositivePattern; set { - // // NOTENOTE: the range of value should correspond to posPercentFormats[] in vm\COMNumber.cpp. - // if (value < 0 || value > 3) { throw new ArgumentOutOfRangeException( - nameof(PercentPositivePattern), - SR.Format( - SR.ArgumentOutOfRange_Range, - 0, - 3)); + nameof(value), + value, + SR.Format(SR.ArgumentOutOfRange_Range, 0, 3)); } + VerifyWritable(); - percentPositivePattern = value; + _percentPositivePattern = value; } } - public int PercentNegativePattern { - get { return percentNegativePattern; } + get => _percentNegativePattern; set { - // // NOTENOTE: the range of value should correspond to posPercentFormats[] in vm\COMNumber.cpp. - // if (value < 0 || value > 11) { throw new ArgumentOutOfRangeException( - nameof(PercentNegativePattern), - SR.Format( - SR.ArgumentOutOfRange_Range, - 0, - 11)); + nameof(value), + value, + SR.Format(SR.ArgumentOutOfRange_Range, 0, 11)); } + VerifyWritable(); - percentNegativePattern = value; + _percentNegativePattern = value; } } - public string NegativeInfinitySymbol { - get - { - return negativeInfinitySymbol; - } + get => _negativeInfinitySymbol; set { if (value == null) { - throw new ArgumentNullException(nameof(NegativeInfinitySymbol), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); - negativeInfinitySymbol = value; + _negativeInfinitySymbol = value; } } - public string NegativeSign { - get { return negativeSign; } + get => _negativeSign; set { if (value == null) { - throw new ArgumentNullException(nameof(NegativeSign), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); - negativeSign = value; + _negativeSign = value; UpdateHasInvariantNumberSigns(); } } - public int NumberDecimalDigits { - get { return numberDecimalDigits; } + get => _numberDecimalDigits; set { if (value < 0 || value > 99) { throw new ArgumentOutOfRangeException( - nameof(NumberDecimalDigits), - SR.Format( - SR.ArgumentOutOfRange_Range, - 0, - 99)); + nameof(value), + value, + SR.Format(SR.ArgumentOutOfRange_Range, 0, 99)); } + VerifyWritable(); - numberDecimalDigits = value; + _numberDecimalDigits = value; } } - public string NumberDecimalSeparator { - get { return numberDecimalSeparator; } + get => _numberDecimalSeparator; set { VerifyWritable(); - VerifyDecimalSeparator(value, nameof(NumberDecimalSeparator)); - numberDecimalSeparator = value; + VerifyDecimalSeparator(value, nameof(value)); + _numberDecimalSeparator = value; } } - public string NumberGroupSeparator { - get { return numberGroupSeparator; } + get => _numberGroupSeparator; set { VerifyWritable(); - VerifyGroupSeparator(value, nameof(NumberGroupSeparator)); - numberGroupSeparator = value; + VerifyGroupSeparator(value, nameof(value)); + _numberGroupSeparator = value; } } - public int CurrencyPositivePattern { - get { return currencyPositivePattern; } + get => _currencyPositivePattern; set { if (value < 0 || value > 3) { throw new ArgumentOutOfRangeException( - nameof(CurrencyPositivePattern), - SR.Format( - SR.ArgumentOutOfRange_Range, - 0, - 3)); + nameof(value), + value, + SR.Format(SR.ArgumentOutOfRange_Range, 0, 3)); } + VerifyWritable(); - currencyPositivePattern = value; + _currencyPositivePattern = value; } } - public string PositiveInfinitySymbol { - get - { - return positiveInfinitySymbol; - } + get => _positiveInfinitySymbol; set { if (value == null) { - throw new ArgumentNullException(nameof(PositiveInfinitySymbol), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); - positiveInfinitySymbol = value; + _positiveInfinitySymbol = value; } } - public string PositiveSign { - get { return positiveSign; } + get => _positiveSign; set { if (value == null) { - throw new ArgumentNullException(nameof(PositiveSign), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); - positiveSign = value; + _positiveSign = value; UpdateHasInvariantNumberSigns(); } } - public int PercentDecimalDigits { - get { return percentDecimalDigits; } + get => _percentDecimalDigits; set { if (value < 0 || value > 99) { throw new ArgumentOutOfRangeException( - nameof(PercentDecimalDigits), - SR.Format( - SR.ArgumentOutOfRange_Range, - 0, - 99)); + nameof(value), + value, + SR.Format(SR.ArgumentOutOfRange_Range, 0, 99)); } + VerifyWritable(); - percentDecimalDigits = value; + _percentDecimalDigits = value; } } public string PercentDecimalSeparator { - get { return percentDecimalSeparator; } + get => _percentDecimalSeparator; set { VerifyWritable(); - VerifyDecimalSeparator(value, nameof(PercentDecimalSeparator)); - percentDecimalSeparator = value; + VerifyDecimalSeparator(value, nameof(value)); + _percentDecimalSeparator = value; } } public string PercentGroupSeparator { - get { return percentGroupSeparator; } + get => _percentGroupSeparator; set { VerifyWritable(); - VerifyGroupSeparator(value, nameof(PercentGroupSeparator)); - percentGroupSeparator = value; + VerifyGroupSeparator(value, nameof(value)); + _percentGroupSeparator = value; } } public string PercentSymbol { - get - { - return percentSymbol; - } + get => _percentSymbol; set { if (value == null) { - throw new ArgumentNullException(nameof(PercentSymbol), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); - percentSymbol = value; + _percentSymbol = value; } } public string PerMilleSymbol { - get { return perMilleSymbol; } + get => _perMilleSymbol; set { if (value == null) { - throw new ArgumentNullException(nameof(PerMilleSymbol), - SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); - perMilleSymbol = value; + _perMilleSymbol = value; } } public string[] NativeDigits { - get { return (string[])nativeDigits.Clone(); } + get => (string[])_nativeDigits.Clone(); set { VerifyWritable(); - VerifyNativeDigits(value, nameof(NativeDigits)); - nativeDigits = value; + VerifyNativeDigits(value, nameof(value)); + _nativeDigits = value; } } public DigitShapes DigitSubstitution { - get { return (DigitShapes)digitSubstitution; } + get => (DigitShapes)_digitSubstitution; set { VerifyWritable(); - VerifyDigitSubstitution(value, nameof(DigitSubstitution)); - digitSubstitution = (int)value; + VerifyDigitSubstitution(value, nameof(value)); + _digitSubstitution = (int)value; } } @@ -772,12 +711,14 @@ namespace System.Globalization { throw new ArgumentNullException(nameof(nfi)); } + if (nfi.IsReadOnly) { - return (nfi); + return nfi; } + NumberFormatInfo info = (NumberFormatInfo)(nfi.MemberwiseClone()); - info.isReadOnly = true; + info._isReadOnly = true; return info; } @@ -802,6 +743,7 @@ namespace System.Globalization { throw new ArgumentException(SR.Argument_InvalidNumberStyles, nameof(style)); } + throw new ArgumentException(SR.Arg_InvalidHexStyle); } } @@ -820,18 +762,10 @@ namespace System.Globalization { throw new ArgumentException(SR.Argument_InvalidNumberStyles, nameof(style)); } + throw new ArgumentException(SR.Arg_HexStyleNotSupported); } } } - } // NumberFormatInfo + } } - - - - - - - - - diff --git a/src/System.Private.CoreLib/shared/System/Globalization/NumberStyles.cs b/src/System.Private.CoreLib/shared/System/Globalization/NumberStyles.cs index 5909d65..cf5a081 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/NumberStyles.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/NumberStyles.cs @@ -2,49 +2,54 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -/*============================================================ -** -** -** -** Purpose: Contains valid formats for Numbers recognized by -** the Number class' parsing code. -** -** -===========================================================*/ - namespace System.Globalization { + /// + /// Contains valid formats for Numbers recognized by the Number + /// class' parsing code. + /// [Flags] public enum NumberStyles { - // Bit flag indicating that leading whitespace is allowed. Character values - // 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, and 0x0020 are considered to be - // whitespace. - None = 0x00000000, + /// + /// Bit flag indicating that leading whitespace is allowed. Character values + /// 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, and 0x0020 are considered to be + /// whitespace. + /// AllowLeadingWhite = 0x00000001, - AllowTrailingWhite = 0x00000002, //Bitflag indicating trailing whitespace is allowed. - - AllowLeadingSign = 0x00000004, //Can the number start with a sign char. - //Specified by NumberFormatInfo.PositiveSign and NumberFormatInfo.NegativeSign + /// + /// Bitflag indicating trailing whitespace is allowed. + /// + AllowTrailingWhite = 0x00000002, - AllowTrailingSign = 0x00000008, //Allow the number to end with a sign char + /// + /// Can the number start with a sign char specified by + /// NumberFormatInfo.PositiveSign and NumberFormatInfo.NegativeSign + /// + AllowLeadingSign = 0x00000004, - AllowParentheses = 0x00000010, //Allow the number to be enclosed in parens + /// + /// Allow the number to end with a sign char + /// + AllowTrailingSign = 0x00000008, - AllowDecimalPoint = 0x00000020, //Allow a decimal point + /// + /// Allow the number to be enclosed in parens + /// + AllowParentheses = 0x00000010, - AllowThousands = 0x00000040, //Allow thousands separators (more properly, allow group separators) + AllowDecimalPoint = 0x00000020, - AllowExponent = 0x00000080, //Allow an exponent + AllowThousands = 0x00000040, - AllowCurrencySymbol = 0x00000100, //Allow a currency symbol. + AllowExponent = 0x00000080, - AllowHexSpecifier = 0x00000200, //Allow specifiying hexadecimal. - //Common uses. These represent some of the most common combinations of these flags. + AllowCurrencySymbol = 0x00000100, + AllowHexSpecifier = 0x00000200, Integer = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign, diff --git a/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs index 7296123..03bed85 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs @@ -2,89 +2,61 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -//////////////////////////////////////////////////////////////////////////// -// -// -// Purpose: This class represents settings specified by de jure or -// de facto standards for a particular country/region. In -// contrast to CultureInfo, the RegionInfo does not represent -// preferences of the user and does not depend on the user's -// language or culture. -// -// -//////////////////////////////////////////////////////////////////////////// - using System.Diagnostics; namespace System.Globalization { + /// + /// This class represents settings specified by de jure or de facto + /// standards for a particular country/region. In contrast to + /// CultureInfo, the RegionInfo does not represent preferences of the + /// user and does not depend on the user's language or culture. + /// public class RegionInfo { - //--------------------------------------------------------------------// - // Internal Information // - //--------------------------------------------------------------------// - - // - // Variables. - // - - // // Name of this region (ie: es-US): serialized, the field used for deserialization - // - internal string _name; + private string _name; - // // The CultureData instance that we are going to read data from. - // - internal CultureData _cultureData; + private readonly CultureData _cultureData; - // // The RegionInfo for our current region - // internal static volatile RegionInfo s_currentRegionInfo; - - //////////////////////////////////////////////////////////////////////// - // - // RegionInfo Constructors - // - // Note: We prefer that a region be created with a full culture name (ie: en-US) - // because otherwise the native strings won't be right. - // - // In Silverlight we enforce that RegionInfos must be created with a full culture name - // - //////////////////////////////////////////////////////////////////////// public RegionInfo(string name) { if (name == null) + { throw new ArgumentNullException(nameof(name)); + } - if (name.Length == 0) //The InvariantCulture has no matching region + // The InvariantCulture has no matching region + if (name.Length == 0) { throw new ArgumentException(SR.Argument_NoRegionInvariantCulture, nameof(name)); } - - // // For CoreCLR we only want the region names that are full culture names - // _cultureData = CultureData.GetCultureDataForRegion(name, true); if (_cultureData == null) - throw new ArgumentException( - SR.Format(SR.Argument_InvalidCultureName, name), nameof(name)); - + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidCultureName, name), nameof(name)); + } // Not supposed to be neutral if (_cultureData.IsNeutralCulture) + { throw new ArgumentException(SR.Format(SR.Argument_InvalidNeutralRegionName, name), nameof(name)); + } SetName(name); } public RegionInfo(int culture) { - if (culture == CultureInfo.LOCALE_INVARIANT) //The InvariantCulture has no matching region - { + // The InvariantCulture has no matching region + if (culture == CultureInfo.LOCALE_INVARIANT) + { throw new ArgumentException(SR.Argument_NoRegionInvariantCulture); } @@ -99,9 +71,9 @@ namespace System.Globalization // Not supposed to be neutral throw new ArgumentException(SR.Format(SR.Argument_CustomCultureCannotBePassedByNumber, culture), nameof(culture)); } - + _cultureData = CultureData.GetCultureData(culture, true); - _name = _cultureData.SREGIONNAME; + _name = _cultureData.RegionName; if (_cultureData.IsNeutralCulture) { @@ -113,24 +85,19 @@ namespace System.Globalization internal RegionInfo(CultureData cultureData) { _cultureData = cultureData; - _name = _cultureData.SREGIONNAME; + _name = _cultureData.RegionName; } private void SetName(string name) { // Use the name of the region we found - _name = _cultureData.SREGIONNAME; + _name = _cultureData.RegionName; } - //////////////////////////////////////////////////////////////////////// - // - // GetCurrentRegion - // - // This instance provides methods based on the current user settings. - // These settings are volatile and may change over the lifetime of the - // thread. - // - //////////////////////////////////////////////////////////////////////// + /// + /// This instance provides methods based on the current user settings. + /// These settings are volatile and may change over the lifetime of the + /// public static RegionInfo CurrentRegion { get @@ -141,256 +108,100 @@ namespace System.Globalization temp = new RegionInfo(CultureInfo.CurrentCulture._cultureData); // Need full name for custom cultures - temp._name = temp._cultureData.SREGIONNAME; + temp._name = temp._cultureData.RegionName; s_currentRegionInfo = temp; } return temp; } } - //////////////////////////////////////////////////////////////////////// - // - // GetName - // - // Returns the name of the region (ie: en-US) - // - //////////////////////////////////////////////////////////////////////// + /// + /// Returns the name of the region (ie: en-US) + /// public virtual string Name { get { Debug.Assert(_name != null, "Expected RegionInfo._name to be populated already"); - return (_name); - } - } - - //////////////////////////////////////////////////////////////////////// - // - // GetEnglishName - // - // Returns the name of the region in English. (ie: United States) - // - //////////////////////////////////////////////////////////////////////// - public virtual string EnglishName - { - get - { - return (_cultureData.SENGCOUNTRY); - } - } - - - //////////////////////////////////////////////////////////////////////// - // - // GetDisplayName - // - // Returns the display name (localized) of the region. (ie: United States - // if the current UI language is en-US) - // - //////////////////////////////////////////////////////////////////////// - public virtual string DisplayName - { - get - { - return (_cultureData.SLOCALIZEDCOUNTRY); - } - } - - - //////////////////////////////////////////////////////////////////////// - // - // GetNativeName - // - // Returns the native name of the region. (ie: Deutschland) - // WARNING: You need a full locale name for this to make sense. - // - //////////////////////////////////////////////////////////////////////// - public virtual string NativeName - { - get - { - return (_cultureData.SNATIVECOUNTRY); - } - } - - //////////////////////////////////////////////////////////////////////// - // - // TwoLetterISORegionName - // - // Returns the two letter ISO region name (ie: US) - // - //////////////////////////////////////////////////////////////////////// - public virtual string TwoLetterISORegionName - { - get - { - return (_cultureData.SISO3166CTRYNAME); - } - } - - //////////////////////////////////////////////////////////////////////// - // - // ThreeLetterISORegionName - // - // Returns the three letter ISO region name (ie: USA) - // - //////////////////////////////////////////////////////////////////////// - public virtual string ThreeLetterISORegionName - { - get - { - return (_cultureData.SISO3166CTRYNAME2); - } - } - - //////////////////////////////////////////////////////////////////////// - // - // ThreeLetterWindowsRegionName - // - // Returns the three letter windows region name (ie: USA) - // - //////////////////////////////////////////////////////////////////////// - public virtual string ThreeLetterWindowsRegionName - { - get - { - // ThreeLetterWindowsRegionName is really same as ThreeLetterISORegionName - return ThreeLetterISORegionName; - } - } - - - //////////////////////////////////////////////////////////////////////// - // - // IsMetric - // - // Returns true if this region uses the metric measurement system - // - //////////////////////////////////////////////////////////////////////// - public virtual bool IsMetric - { - get - { - int value = _cultureData.IMEASURE; - return (value == 0); - } - } - - public virtual int GeoId - { - get - { - return (_cultureData.IGEOID); - } - } - - //////////////////////////////////////////////////////////////////////// - // - // CurrencyEnglishName - // - // English name for this region's currency, ie: Swiss Franc - // - //////////////////////////////////////////////////////////////////////// - public virtual string CurrencyEnglishName - { - get - { - return (_cultureData.SENGLISHCURRENCY); - } - } - - //////////////////////////////////////////////////////////////////////// - // - // CurrencyNativeName - // - // Native name for this region's currency, ie: Schweizer Franken - // WARNING: You need a full locale name for this to make sense. - // - //////////////////////////////////////////////////////////////////////// - public virtual string CurrencyNativeName - { - get - { - return (_cultureData.SNATIVECURRENCY); - } - } - - //////////////////////////////////////////////////////////////////////// - // - // CurrencySymbol - // - // Currency Symbol for this locale, ie: Fr. or $ - // - //////////////////////////////////////////////////////////////////////// - public virtual string CurrencySymbol - { - get - { - return (_cultureData.SCURRENCY); - } - } - - //////////////////////////////////////////////////////////////////////// - // - // ISOCurrencySymbol - // - // ISO Currency Symbol for this locale, ie: CHF - // - //////////////////////////////////////////////////////////////////////// - public virtual string ISOCurrencySymbol - { - get - { - return (_cultureData.SINTLSYMBOL); - } - } - - //////////////////////////////////////////////////////////////////////// - // - // Equals - // - // Implements Object.Equals(). Returns a boolean indicating whether - // or not object refers to the same RegionInfo as the current instance. - // - // RegionInfos are considered equal if and only if they have the same name - // (ie: en-US) - // - //////////////////////////////////////////////////////////////////////// + return _name; + } + } + + /// + /// Returns the name of the region in English. (ie: United States) + /// + public virtual string EnglishName => _cultureData.EnglishCountryName; + + /// + /// Returns the display name (localized) of the region. (ie: United States + /// if the current UI language is en-US) + /// + public virtual string DisplayName => _cultureData.LocalizedCountryName; + + /// + /// Returns the native name of the region. (ie: Deutschland) + /// WARNING: You need a full locale name for this to make sense. + /// + public virtual string NativeName => _cultureData.NativeCountryName; + + /// + /// Returns the two letter ISO region name (ie: US) + /// + public virtual string TwoLetterISORegionName => _cultureData.TwoLetterISOCountryName; + + /// + /// Returns the three letter ISO region name (ie: USA) + /// + public virtual string ThreeLetterISORegionName => _cultureData.ThreeLetterISOCountryName; + + /// + /// Returns the three letter windows region name (ie: USA) + /// + public virtual string ThreeLetterWindowsRegionName => ThreeLetterISORegionName; + + + /// + /// Returns true if this region uses the metric measurement system + /// + public virtual bool IsMetric => _cultureData.MeasurementSystem == 0; + + public virtual int GeoId => _cultureData.GeoId; + + /// + /// English name for this region's currency, ie: Swiss Franc + /// + public virtual string CurrencyEnglishName => _cultureData.CurrencyEnglishName; + + /// + /// Native name for this region's currency, ie: Schweizer Franken + /// WARNING: You need a full locale name for this to make sense. + /// + public virtual string CurrencyNativeName => _cultureData.CurrencyNativeName; + + /// + /// Currency Symbol for this locale, ie: Fr. or $ + /// + public virtual string CurrencySymbol => _cultureData.CurrencySymbol; + + /// + /// ISO Currency Symbol for this locale, ie: CHF + /// + public virtual string ISOCurrencySymbol => _cultureData.ISOCurrencySymbol; + + /// + /// Implements Object.Equals(). Returns a boolean indicating whether + /// or not object refers to the same RegionInfo as the current instance. + /// RegionInfos are considered equal if and only if they have the same name + /// (ie: en-US) + /// public override bool Equals(object value) { - if (value is RegionInfo that) - { - return this.Name.Equals(that.Name); - } - - return (false); - } - - //////////////////////////////////////////////////////////////////////// - // - // GetHashCode - // - // Implements Object.GetHashCode(). Returns the hash code for the - // CultureInfo. The hash code is guaranteed to be the same for RegionInfo - // A and B where A.Equals(B) is true. - // - //////////////////////////////////////////////////////////////////////// - public override int GetHashCode() - { - return (this.Name.GetHashCode()); + return value is RegionInfo otherRegion + && Name.Equals(otherRegion.Name); } + public override int GetHashCode() => Name.GetHashCode(); - //////////////////////////////////////////////////////////////////////// - // - // ToString - // - // Implements Object.ToString(). Returns the name of the Region, ie: es-US - // - //////////////////////////////////////////////////////////////////////// - public override string ToString() - { - return (Name); - } + public override string ToString() => Name; } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/SortKey.cs b/src/System.Private.CoreLib/shared/System/Globalization/SortKey.cs index f9c7f68..b00f34b 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/SortKey.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/SortKey.cs @@ -2,37 +2,24 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -//////////////////////////////////////////////////////////////////////////// -// -// -// Purpose: This class implements a set of methods for retrieving -// sort key information. -// -// -//////////////////////////////////////////////////////////////////////////// - -using System; -using System.Runtime.CompilerServices; using System.Diagnostics; namespace System.Globalization { + /// + /// This class implements a set of methods for retrieving + /// public partial class SortKey { - //--------------------------------------------------------------------// - // Internal Information // - //--------------------------------------------------------------------// - - internal string _localeName; // locale identifier - - internal CompareOptions _options; // options - internal string _string; // original string - internal byte[] _keyData; // sortkey data - - // - // The following constructor is designed to be called from CompareInfo to get the - // the sort key of specific string for synthetic culture - // + private readonly string _localeName; + private readonly CompareOptions _options; + private readonly string _string; + private readonly byte[] _keyData; + + /// + /// The following constructor is designed to be called from CompareInfo to get the + /// the sort key of specific string for synthetic culture + /// internal SortKey(string localeName, string str, CompareOptions options, byte[] keyData) { _keyData = keyData; @@ -41,52 +28,32 @@ namespace System.Globalization _string = str; } - //////////////////////////////////////////////////////////////////////// - // - // GetOriginalString - // - // Returns the original string used to create the current instance - // of SortKey. - // - //////////////////////////////////////////////////////////////////////// - public virtual string OriginalString + /// + /// Returns the original string used to create the current instance + /// of SortKey. + /// + public virtual string OriginalString => _string; + + /// + /// Returns a byte array representing the current instance of the + /// sort key. + /// + public virtual byte[] KeyData => (byte[])_keyData.Clone(); + + /// + /// Compares the two sort keys. Returns 0 if the two sort keys are + /// equal, a number less than 0 if sortkey1 is less than sortkey2, + /// and a number greater than 0 if sortkey1 is greater than sortkey2. + /// + public static int Compare(SortKey sortkey1, SortKey sortkey2) { - get + if (sortkey1 == null) { - return (_string); + throw new ArgumentNullException(nameof(sortkey1)); } - } - - //////////////////////////////////////////////////////////////////////// - // - // GetKeyData - // - // Returns a byte array representing the current instance of the - // sort key. - // - //////////////////////////////////////////////////////////////////////// - public virtual byte[] KeyData - { - get + if (sortkey2 == null) { - return (byte[])(_keyData.Clone()); - } - } - - //////////////////////////////////////////////////////////////////////// - // - // Compare - // - // Compares the two sort keys. Returns 0 if the two sort keys are - // equal, a number less than 0 if sortkey1 is less than sortkey2, - // and a number greater than 0 if sortkey1 is greater than sortkey2. - // - //////////////////////////////////////////////////////////////////////// - public static int Compare(SortKey sortkey1, SortKey sortkey2) - { - if (sortkey1 == null || sortkey2 == null) - { - throw new ArgumentNullException((sortkey1 == null ? nameof(sortkey1) : nameof(sortkey2))); + throw new ArgumentNullException(nameof(sortkey2)); } byte[] key1Data = sortkey1._keyData; @@ -99,75 +66,45 @@ namespace System.Globalization { if (key2Data.Length == 0) { - return (0); + return 0; } - return (-1); + + return -1; } if (key2Data.Length == 0) { - return (1); + return 1; } int compLen = (key1Data.Length < key2Data.Length) ? key1Data.Length : key2Data.Length; - for (int i = 0; i < compLen; i++) { if (key1Data[i] > key2Data[i]) { - return (1); + return 1; } if (key1Data[i] < key2Data[i]) { - return (-1); + return -1; } } return 0; } - //////////////////////////////////////////////////////////////////////// - // - // Equals - // - // Implements Object.Equals(). Returns a boolean indicating whether - // or not object refers to the same SortKey as the current instance. - // - //////////////////////////////////////////////////////////////////////// public override bool Equals(object value) { - if (value is SortKey that) - { - return Compare(this, that) == 0; - } - - return (false); + return value is SortKey otherSortKey && Compare(this, otherSortKey) == 0; } - //////////////////////////////////////////////////////////////////////// - // - // GetHashCode - // - // Implements Object.GetHashCode(). Returns the hash code for the - // SortKey. The hash code is guaranteed to be the same for - // SortKey A and B where A.Equals(B) is true. - // - //////////////////////////////////////////////////////////////////////// public override int GetHashCode() { - return (CompareInfo.GetCompareInfo(_localeName).GetHashCodeOfString(_string, _options)); + return CompareInfo.GetCompareInfo(_localeName).GetHashCodeOfString(_string, _options); } - //////////////////////////////////////////////////////////////////////// - // - // ToString - // - // Implements Object.ToString(). Returns a string describing the - // SortKey. - // - //////////////////////////////////////////////////////////////////////// public override string ToString() { - return ("SortKey - " + _localeName + ", " + _options + ", " + _string); + return "SortKey - " + _localeName + ", " + _options + ", " + _string; } } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs b/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs index cb0d4c4..ce86d56 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs @@ -13,21 +13,9 @@ namespace System.Globalization private int m_NlsVersion; // Do not rename (binary serialization) private Guid m_SortId; // Do not rename (binary serialization) - public int FullVersion - { - get - { - return m_NlsVersion; - } - } + public int FullVersion => m_NlsVersion; - public Guid SortId - { - get - { - return m_SortId; - } - } + public Guid SortId => m_SortId; public SortVersion(int fullVersion, Guid sortId) { @@ -53,13 +41,7 @@ namespace System.Globalization public override bool Equals(object obj) { - SortVersion n = obj as SortVersion; - if (n != null) - { - return this.Equals(n); - } - - return false; + return obj is SortVersion otherVersion && Equals(otherVersion); } public bool Equals(SortVersion other) diff --git a/src/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs index 425e6f2..2c9b4da 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs @@ -2,31 +2,25 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -//////////////////////////////////////////////////////////////////////////// -// -// -// Purpose: This class defines behaviors specific to a writing system. -// A writing system is the collection of scripts and -// orthographic rules required to represent a language as text. -// -// -//////////////////////////////////////////////////////////////////////////// - -using System; using System.Diagnostics; namespace System.Globalization { + /// + /// This class defines behaviors specific to a writing system. + /// A writing system is the collection of scripts and orthographic rules + /// required to represent a language as text. + /// public class StringInfo { private string _str; private int[] _indexes; - // Legacy constructor - public StringInfo() : this("") { } + public StringInfo() : this(string.Empty) + { + } - // Primary, useful constructor public StringInfo(string value) { this.String = value; @@ -34,105 +28,76 @@ namespace System.Globalization public override bool Equals(object value) { - if (value is StringInfo that) - { - return (_str.Equals(that._str)); - } - return (false); - } - - public override int GetHashCode() - { - return _str.GetHashCode(); + return value is StringInfo otherStringInfo + && _str.Equals(otherStringInfo._str); } + public override int GetHashCode() => _str.GetHashCode(); - // Our zero-based array of index values into the string. Initialize if - // our private array is not yet, in fact, initialized. + /// + /// Our zero-based array of index values into the string. Initialize if + /// our private array is not yet, in fact, initialized. + /// private int[] Indexes { get { - if ((null == _indexes) && (0 < this.String.Length)) + if (_indexes == null && String.Length > 0) { - _indexes = StringInfo.ParseCombiningCharacters(this.String); + _indexes = StringInfo.ParseCombiningCharacters(String); } - return (_indexes); + return _indexes; } } public string String { - get - { - return (_str); - } + get => _str; set { - if (null == value) - { - throw new ArgumentNullException(nameof(String), - SR.ArgumentNull_String); - } - - _str = value; + _str = value ?? throw new ArgumentNullException(nameof(value)); _indexes = null; } } - public int LengthInTextElements - { - get - { - if (null == this.Indexes) - { - // Indexes not initialized, so assume length zero - return (0); - } - - return (this.Indexes.Length); - } - } + public int LengthInTextElements => Indexes?.Length ?? 0; public string SubstringByTextElements(int startingTextElement) { // If the string is empty, no sense going further. - if (null == this.Indexes) + if (Indexes == null) { - // Just decide which error to give depending on the param they gave us.... if (startingTextElement < 0) { - throw new ArgumentOutOfRangeException(nameof(startingTextElement), SR.ArgumentOutOfRange_NeedPosNum); + throw new ArgumentOutOfRangeException(nameof(startingTextElement), startingTextElement, SR.ArgumentOutOfRange_NeedPosNum); } else { - throw new ArgumentOutOfRangeException(nameof(startingTextElement), SR.Arg_ArgumentOutOfRangeException); + throw new ArgumentOutOfRangeException(nameof(startingTextElement), startingTextElement, SR.Arg_ArgumentOutOfRangeException); } } - return (SubstringByTextElements(startingTextElement, Indexes.Length - startingTextElement)); + + return SubstringByTextElements(startingTextElement, Indexes.Length - startingTextElement); } public string SubstringByTextElements(int startingTextElement, int lengthInTextElements) { if (startingTextElement < 0) { - throw new ArgumentOutOfRangeException(nameof(startingTextElement), SR.ArgumentOutOfRange_NeedPosNum); + throw new ArgumentOutOfRangeException(nameof(startingTextElement), startingTextElement, SR.ArgumentOutOfRange_NeedPosNum); } - - if (this.String.Length == 0 || startingTextElement >= Indexes.Length) + if (String.Length == 0 || startingTextElement >= Indexes.Length) { - throw new ArgumentOutOfRangeException(nameof(startingTextElement), SR.Arg_ArgumentOutOfRangeException); + throw new ArgumentOutOfRangeException(nameof(startingTextElement), startingTextElement, SR.Arg_ArgumentOutOfRangeException); } - if (lengthInTextElements < 0) { - throw new ArgumentOutOfRangeException(nameof(lengthInTextElements), SR.ArgumentOutOfRange_NeedPosNum); + throw new ArgumentOutOfRangeException(nameof(lengthInTextElements), lengthInTextElements, SR.ArgumentOutOfRange_NeedPosNum); } - if (startingTextElement > Indexes.Length - lengthInTextElements) { - throw new ArgumentOutOfRangeException(nameof(lengthInTextElements), SR.Arg_ArgumentOutOfRangeException); + throw new ArgumentOutOfRangeException(nameof(lengthInTextElements), lengthInTextElements, SR.Arg_ArgumentOutOfRangeException); } int start = Indexes[startingTextElement]; @@ -141,52 +106,35 @@ namespace System.Globalization { // We are at the last text element in the string and because of that // must handle the call differently. - return (this.String.Substring(start)); + return String.Substring(start); } else { - return (this.String.Substring(start, (Indexes[lengthInTextElements + startingTextElement] - start))); + return String.Substring(start, Indexes[lengthInTextElements + startingTextElement] - start); } } - public static string GetNextTextElement(string str) - { - return (GetNextTextElement(str, 0)); - } - - - //////////////////////////////////////////////////////////////////////// - // - // Get the code point count of the current text element. - // - // A combining class is defined as: - // A character/surrogate that has the following Unicode category: - // * NonSpacingMark (e.g. U+0300 COMBINING GRAVE ACCENT) - // * SpacingCombiningMark (e.g. U+ 0903 DEVANGARI SIGN VISARGA) - // * EnclosingMark (e.g. U+20DD COMBINING ENCLOSING CIRCLE) - // - // In the context of GetNextTextElement() and ParseCombiningCharacters(), a text element is defined as: - // - // 1. If a character/surrogate is in the following category, it is a text element. - // It can NOT further combine with characters in the combinging class to form a text element. - // * one of the Unicode category in the combinging class - // * UnicodeCategory.Format - // * UnicodeCateogry.Control - // * UnicodeCategory.OtherNotAssigned - // 2. Otherwise, the character/surrogate can be combined with characters in the combinging class to form a text element. - // - // Return: - // The length of the current text element - // - // Parameters: - // String str - // index The starting index - // len The total length of str (to define the upper boundary) - // ucCurrent The Unicode category pointed by Index. It will be updated to the uc of next character if this is not the last text element. - // currentCharCount The char count of an abstract char pointed by Index. It will be updated to the char count of next abstract character if this is not the last text element. - // - //////////////////////////////////////////////////////////////////////// - + public static string GetNextTextElement(string str) => GetNextTextElement(str, 0); + + /// + /// Get the code point count of the current text element. + /// + /// A combining class is defined as: + /// A character/surrogate that has the following Unicode category: + /// * NonSpacingMark (e.g. U+0300 COMBINING GRAVE ACCENT) + /// * SpacingCombiningMark (e.g. U+ 0903 DEVANGARI SIGN VISARGA) + /// * EnclosingMark (e.g. U+20DD COMBINING ENCLOSING CIRCLE) + /// + /// In the context of GetNextTextElement() and ParseCombiningCharacters(), a text element is defined as: + /// 1. If a character/surrogate is in the following category, it is a text element. + /// It can NOT further combine with characters in the combinging class to form a text element. + /// * one of the Unicode category in the combinging class + /// * UnicodeCategory.Format + /// * UnicodeCateogry.Control + /// * UnicodeCategory.OtherNotAssigned + /// 2. Otherwise, the character/surrogate can be combined with characters in the combinging class to form a text element. + /// + /// The length of the current text element internal static int GetCurrentTextElementLen(string str, int index, int len, ref UnicodeCategory ucCurrent, ref int currentCharCount) { Debug.Assert(index >= 0 && len >= 0, "StringInfo.GetCurrentTextElementLen() : index = " + index + ", len = " + len); @@ -194,7 +142,7 @@ namespace System.Globalization if (index + currentCharCount == len) { // This is the last character/surrogate in the string. - return (currentCharCount); + return currentCharCount; } // Call an internal GetUnicodeCategory, which will tell us both the unicode category, and also tell us if it is a surrogate pair or not. @@ -205,7 +153,6 @@ namespace System.Globalization // The next element is a combining class. // Check if the current text element to see if it is a valid base category (i.e. it should not be a combining category, // not a format character, and not a control character). - if (CharUnicodeInfo.IsCombiningCategory(ucCurrent) || (ucCurrent == UnicodeCategory.Format) || (ucCurrent == UnicodeCategory.Control) @@ -216,7 +163,8 @@ namespace System.Globalization } else { - int startIndex = index; // Remember the current index. + // Remember the current index. + int startIndex = index; // We have a valid base characters, and we have a character (or surrogate) that is combining. // Check if there are more combining characters to follow. @@ -234,27 +182,28 @@ namespace System.Globalization } index += nextCharCount; } - return (index - startIndex); + + return index - startIndex; } } + // The return value will be the currentCharCount. int ret = currentCharCount; ucCurrent = ucNext; // Update currentCharCount. currentCharCount = nextCharCount; - return (ret); + return ret; } - // Returns the str containing the next text element in str starting at - // index index. If index is not supplied, then it will start at the beginning - // of str. It recognizes a base character plus one or more combining - // characters or a properly formed surrogate pair as a text element. See also - // the ParseCombiningCharacters() and the ParseSurrogates() methods. + /// + /// Returns the str containing the next text element in str starting at + /// index index. If index is not supplied, then it will start at the beginning + /// of str. It recognizes a base character plus one or more combining + /// characters or a properly formed surrogate pair as a text element. + /// See also the ParseCombiningCharacters() and the ParseSurrogates() methods. + /// public static string GetNextTextElement(string str, int index) { - // - // Validate parameters. - // if (str == null) { throw new ArgumentNullException(nameof(str)); @@ -265,52 +214,50 @@ namespace System.Globalization { if (index == len) { - return (string.Empty); + return string.Empty; } - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + + throw new ArgumentOutOfRangeException(nameof(index), index, SR.ArgumentOutOfRange_Index); } int charLen; UnicodeCategory uc = CharUnicodeInfo.InternalGetUnicodeCategory(str, index, out charLen); - return (str.Substring(index, GetCurrentTextElementLen(str, index, len, ref uc, ref charLen))); + return str.Substring(index, GetCurrentTextElementLen(str, index, len, ref uc, ref charLen)); } public static TextElementEnumerator GetTextElementEnumerator(string str) { - return (GetTextElementEnumerator(str, 0)); + return GetTextElementEnumerator(str, 0); } public static TextElementEnumerator GetTextElementEnumerator(string str, int index) { - // - // Validate parameters. - // if (str == null) { throw new ArgumentNullException(nameof(str)); } int len = str.Length; - if (index < 0 || (index > len)) + if (index < 0 || index > len) { - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + throw new ArgumentOutOfRangeException(nameof(index), index, SR.ArgumentOutOfRange_Index); } - return (new TextElementEnumerator(str, index, len)); + return new TextElementEnumerator(str, index, len); } - /* - * Returns the indices of each base character or properly formed surrogate pair - * within the str. It recognizes a base character plus one or more combining - * characters or a properly formed surrogate pair as a text element and returns - * the index of the base character or high surrogate. Each index is the - * beginning of a text element within a str. The length of each element is - * easily computed as the difference between successive indices. The length of - * the array will always be less than or equal to the length of the str. For - * example, given the str \u4f00\u302a\ud800\udc00\u4f01, this method would - * return the indices: 0, 2, 4. - */ - + /// + /// Returns the indices of each base character or properly formed surrogate + /// pair within the str. It recognizes a base character plus one or more + /// combining characters or a properly formed surrogate pair as a text + /// element and returns the index of the base character or high surrogate. + /// Each index is the beginning of a text element within a str. The length + /// of each element is easily computed as the difference between successive + /// indices. The length of the array will always be less than or equal to + /// the length of the str. For example, given the str + /// \u4f00\u302a\ud800\udc00\u4f01, this method would return the indices: + /// 0, 2, 4. + /// public static int[] ParseCombiningCharacters(string str) { if (str == null) @@ -343,7 +290,7 @@ namespace System.Globalization Array.Copy(result, 0, returnArray, 0, resultCount); return (returnArray); } - return (result); + return result; } } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs b/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs index 7d8ff64..60d2a10 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs @@ -2,36 +2,28 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -//////////////////////////////////////////////////////////////////////////// -// -// -// Purpose: -// -// -//////////////////////////////////////////////////////////////////////////// - using System.Collections; using System.Diagnostics; namespace System.Globalization { - // - // This is public because GetTextElement() is public. - // - public class TextElementEnumerator : IEnumerator { - private string _str; + private readonly string _str; private int _index; - private int _startIndex; + private readonly int _startIndex; - private int _strLen; // This is the length of the total string, counting from the beginning of string. + // This is the length of the total string, counting from the beginning of string. + private readonly int _strLen; - private int _currTextElementLen; // The current text element lenght after MoveNext() is called. + // The current text element lenght after MoveNext() is called. + private int _currTextElementLen; private UnicodeCategory _uc; - private int _charLen; // The next abstract char to look at after MoveNext() is called. It could be 1 or 2, depending on if it is a surrogate or not. + // The next abstract char to look at after MoveNext() is called. + // It could be 1 or 2, depending on if it is a surrogate or not. + private int _charLen; internal TextElementEnumerator(string str, int startIndex, int strLen) { @@ -50,28 +42,15 @@ namespace System.Globalization { // Make the _index to be greater than _strLen so that we can throw exception if GetTextElement() is called. _index = _strLen + 1; - return (false); + return false; } + _currTextElementLen = StringInfo.GetCurrentTextElementLen(_str, _index, _strLen, ref _uc, ref _charLen); _index += _currTextElementLen; - return (true); + return true; } - // - // Get the current text element. - // - - public object Current - { - get - { - return (GetTextElement()); - } - } - - // - // Get the current text element. - // + public object Current => GetTextElement(); public string GetTextElement() { @@ -84,13 +63,9 @@ namespace System.Globalization throw new InvalidOperationException(SR.InvalidOperation_EnumEnded); } - return (_str.Substring(_index - _currTextElementLen, _currTextElementLen)); + return _str.Substring(_index - _currTextElementLen, _currTextElementLen); } - // - // Get the starting index of the current text element. - // - public int ElementIndex { get @@ -99,11 +74,11 @@ namespace System.Globalization { throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted); } - return (_index - _currTextElementLen); + + return _index - _currTextElementLen; } } - public void Reset() { _index = _startIndex; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs index 77964fb..12ce6d9 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs @@ -2,16 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -//////////////////////////////////////////////////////////////////////////// -// -// -// Purpose: This Class defines behaviors specific to a writing system. -// A writing system is the collection of scripts and -// orthographic rules required to represent a language as text. -// -// -//////////////////////////////////////////////////////////////////////////// - using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -29,6 +19,11 @@ using nint = System.Int32; namespace System.Globalization { + /// + /// This Class defines behaviors specific to a writing system. + /// A writing system is the collection of scripts and orthographic rules + /// required to represent a language as text. + /// public partial class TextInfo : ICloneable, IDeserializationCallback { private enum Tristate : byte @@ -41,44 +36,28 @@ namespace System.Globalization private string _listSeparator; private bool _isReadOnly = false; - /* _cultureName is the name of the creating culture. - _cultureData is the data that backs this class. - _textInfoName is the actual name of the textInfo (from cultureData.STEXTINFO) - In the desktop, when we call the sorting dll, it doesn't - know how to resolve custom locle names to sort ids so we have to have already resolved this. - */ + private readonly string _cultureName; + private readonly CultureData _cultureData; - private readonly string _cultureName; // Name of the culture that created this text info - private readonly CultureData _cultureData; // Data record for the culture that made us, not for this textinfo - private readonly string _textInfoName; // Name of the text info we're using (ie: _cultureData.STEXTINFO) + // // Name of the text info we're using (ie: _cultureData.TextInfoName) + private readonly string _textInfoName; private Tristate _isAsciiCasingSameAsInvariant = Tristate.NotInitialized; // Invariant text info internal static TextInfo Invariant { - get - { - if (s_Invariant == null) - s_Invariant = new TextInfo(CultureData.Invariant); - return s_Invariant; - } + get => s_invariant ?? (s_invariant = new TextInfo(CultureData.Invariant)); } - internal volatile static TextInfo s_Invariant; - ////////////////////////////////////////////////////////////////////////// - //// - //// TextInfo Constructors - //// - //// Implements CultureInfo.TextInfo. - //// - ////////////////////////////////////////////////////////////////////////// + private volatile static TextInfo s_invariant; + internal TextInfo(CultureData cultureData) { // This is our primary data source, we don't need most of the rest of this _cultureData = cultureData; _cultureName = _cultureData.CultureName; - _textInfoName = _cultureData.STEXTINFO; + _textInfoName = _cultureData.TextInfoName; FinishInitialization(); } @@ -88,13 +67,13 @@ namespace System.Globalization throw new PlatformNotSupportedException(); } - public virtual int ANSICodePage => _cultureData.IDEFAULTANSICODEPAGE; + public virtual int ANSICodePage => _cultureData.ANSICodePage; - public virtual int OEMCodePage => _cultureData.IDEFAULTOEMCODEPAGE; + public virtual int OEMCodePage => _cultureData.OEMCodePage; - public virtual int MacCodePage => _cultureData.IDEFAULTMACCODEPAGE; + public virtual int MacCodePage => _cultureData.MacCodePage; - public virtual int EBCDICCodePage => _cultureData.IDEFAULTEBCDICCODEPAGE; + public virtual int EBCDICCodePage => _cultureData.EBCDICCodePage; // Just use the LCID from our text info name public int LCID => CultureInfo.GetCultureInfo(_textInfoName).LCID; @@ -103,13 +82,6 @@ namespace System.Globalization public bool IsReadOnly => _isReadOnly; - ////////////////////////////////////////////////////////////////////////// - //// - //// Clone - //// - //// Is the implementation of ICloneable. - //// - ////////////////////////////////////////////////////////////////////////// public virtual object Clone() { object o = MemberwiseClone(); @@ -117,22 +89,24 @@ namespace System.Globalization return o; } - //////////////////////////////////////////////////////////////////////// - // - // ReadOnly - // - // Create a cloned readonly instance or return the input one if it is - // readonly. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Create a cloned readonly instance or return the input one if it is + /// readonly. + /// public static TextInfo ReadOnly(TextInfo textInfo) { - if (textInfo == null) { throw new ArgumentNullException(nameof(textInfo)); } - if (textInfo.IsReadOnly) { return textInfo; } + if (textInfo == null) + { + throw new ArgumentNullException(nameof(textInfo)); + } + + if (textInfo.IsReadOnly) + { + return textInfo; + } TextInfo clonedTextInfo = (TextInfo)(textInfo.MemberwiseClone()); clonedTextInfo.SetReadOnlyState(true); - return clonedTextInfo; } @@ -150,43 +124,28 @@ namespace System.Globalization } - //////////////////////////////////////////////////////////////////////// - // - // ListSeparator - // - // Returns the string used to separate items in a list. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Returns the string used to separate items in a list. + /// public virtual string ListSeparator { - get - { - if (_listSeparator == null) - { - _listSeparator = _cultureData.SLIST; - } - return _listSeparator; - } - + get => _listSeparator ?? (_listSeparator = _cultureData.ListSeparator); set { if (value == null) { - throw new ArgumentNullException(nameof(value), SR.ArgumentNull_String); + throw new ArgumentNullException(nameof(value)); } + VerifyWritable(); _listSeparator = value; } } - //////////////////////////////////////////////////////////////////////// - // - // ToLower - // - // Converts the character or string to lower case. Certain locales - // have different casing semantics from the file systems in Win32. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Converts the character or string to lower case. Certain locales + /// have different casing semantics from the file systems in Win32. + /// public virtual char ToLower(char c) { if (GlobalizationMode.Invariant || (IsAscii(c) && IsAsciiCasingSameAsInvariant)) @@ -199,7 +158,10 @@ namespace System.Globalization public virtual string ToLower(string str) { - if (str == null) { throw new ArgumentNullException(nameof(str)); } + if (str == null) + { + throw new ArgumentNullException(nameof(str)); + } if (GlobalizationMode.Invariant) { @@ -212,12 +174,12 @@ namespace System.Globalization private unsafe char ChangeCase(char c, bool toUpper) { Debug.Assert(!GlobalizationMode.Invariant); - + char dst = default; ChangeCase(&c, 1, &dst, 1, toUpper); return dst; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ChangeCaseToLower(ReadOnlySpan source, Span destination) { @@ -457,7 +419,7 @@ namespace System.Globalization { return string.Empty; } - + fixed (char* pSource = s) { int i = 0; @@ -469,7 +431,7 @@ namespace System.Globalization } i++; } - + if (i >= s.Length) { return s; @@ -482,7 +444,7 @@ namespace System.Globalization { pResult[j] = pSource[j]; } - + pResult[i] = (char)(pSource[i] | 0x20); i++; @@ -513,7 +475,7 @@ namespace System.Globalization { return string.Empty; } - + fixed (char* pSource = s) { int i = 0; @@ -525,7 +487,7 @@ namespace System.Globalization } i++; } - + if (i >= s.Length) { return s; @@ -538,7 +500,7 @@ namespace System.Globalization { pResult[j] = pSource[j]; } - + pResult[i] = (char)(pSource[i] & ~0x20); i++; @@ -572,27 +534,26 @@ namespace System.Globalization return c; } - //////////////////////////////////////////////////////////////////////// - // - // ToUpper - // - // Converts the character or string to upper case. Certain locales - // have different casing semantics from the file systems in Win32. - // - //////////////////////////////////////////////////////////////////////// + /// + /// Converts the character or string to upper case. Certain locales + /// have different casing semantics from the file systems in Win32. + /// public virtual char ToUpper(char c) { if (GlobalizationMode.Invariant || (IsAscii(c) && IsAsciiCasingSameAsInvariant)) { return ToUpperAsciiInvariant(c); } - + return ChangeCase(c, toUpper: true); } public virtual string ToUpper(string str) { - if (str == null) { throw new ArgumentNullException(nameof(str)); } + if (str == null) + { + throw new ArgumentNullException(nameof(str)); + } if (GlobalizationMode.Invariant) { @@ -611,10 +572,7 @@ namespace System.Globalization return c; } - private static bool IsAscii(char c) - { - return c < 0x80; - } + private static bool IsAscii(char c) => c < 0x80; private bool IsAsciiCasingSameAsInvariant { @@ -627,7 +585,7 @@ namespace System.Globalization } Debug.Assert(_isAsciiCasingSameAsInvariant == Tristate.True || _isAsciiCasingSameAsInvariant == Tristate.False); - return (_isAsciiCasingSameAsInvariant == Tristate.True); + return _isAsciiCasingSameAsInvariant == Tristate.True; } } @@ -638,77 +596,44 @@ namespace System.Globalization _isAsciiCasingSameAsInvariant = (compareResult) ? Tristate.True : Tristate.False; } - // IsRightToLeft - // - // Returns true if the dominant direction of text and UI such as the relative position of buttons and scroll bars - // + /// + /// Returns true if the dominant direction of text and UI such as the + /// relative position of buttons and scroll bars + /// public bool IsRightToLeft => _cultureData.IsRightToLeft; - //////////////////////////////////////////////////////////////////////// - // - // Equals - // - // Implements Object.Equals(). Returns a boolean indicating whether - // or not object refers to the same CultureInfo as the current instance. - // - //////////////////////////////////////////////////////////////////////// public override bool Equals(object obj) { - if (obj is TextInfo that) - { - return CultureName.Equals(that.CultureName); - } - - return false; + return obj is TextInfo otherTextInfo + && CultureName.Equals(otherTextInfo.CultureName); } - //////////////////////////////////////////////////////////////////////// - // - // GetHashCode - // - // Implements Object.GetHashCode(). Returns the hash code for the - // CultureInfo. The hash code is guaranteed to be the same for CultureInfo A - // and B where A.Equals(B) is true. - // - //////////////////////////////////////////////////////////////////////// - public override int GetHashCode() - { - return CultureName.GetHashCode(); - } + public override int GetHashCode() => CultureName.GetHashCode(); - //////////////////////////////////////////////////////////////////////// - // - // ToString - // - // Implements Object.ToString(). Returns a string describing the - // TextInfo. - // - //////////////////////////////////////////////////////////////////////// public override string ToString() { return "TextInfo - " + _cultureData.CultureName; } - // - // Titlecasing: - // ----------- - // Titlecasing refers to a casing practice wherein the first letter of a word is an uppercase letter - // and the rest of the letters are lowercase. The choice of which words to titlecase in headings - // and titles is dependent on language and local conventions. For example, "The Merry Wives of Windor" - // is the appropriate titlecasing of that play's name in English, with the word "of" not titlecased. - // In German, however, the title is "Die lustigen Weiber von Windsor," and both "lustigen" and "von" - // are not titlecased. In French even fewer words are titlecased: "Les joyeuses commeres de Windsor." - // - // Moreover, the determination of what actually constitutes a word is language dependent, and this can - // influence which letter or letters of a "word" are uppercased when titlecasing strings. For example - // "l'arbre" is considered two words in French, whereas "can't" is considered one word in English. - // + /// + /// Titlecasing refers to a casing practice wherein the first letter of a word is an uppercase letter + /// and the rest of the letters are lowercase. The choice of which words to titlecase in headings + /// and titles is dependent on language and local conventions. For example, "The Merry Wives of Windor" + /// is the appropriate titlecasing of that play's name in English, with the word "of" not titlecased. + /// In German, however, the title is "Die lustigen Weiber von Windsor," and both "lustigen" and "von" + /// are not titlecased. In French even fewer words are titlecased: "Les joyeuses commeres de Windsor." + /// + /// Moreover, the determination of what actually constitutes a word is language dependent, and this can + /// influence which letter or letters of a "word" are uppercased when titlecasing strings. For example + /// "l'arbre" is considered two words in French, whereas "can't" is considered one word in English. + /// public unsafe string ToTitleCase(string str) { if (str == null) { throw new ArgumentNullException(nameof(str)); } + if (str.Length == 0) { return str; @@ -721,13 +646,11 @@ namespace System.Globalization for (int i = 0; i < str.Length; i++) { - UnicodeCategory charType; int charLen; - - charType = CharUnicodeInfo.InternalGetUnicodeCategory(str, i, out charLen); + UnicodeCategory charType = CharUnicodeInfo.InternalGetUnicodeCategory(str, i, out charLen); if (char.CheckLetter(charType)) { - // Special case to check for Dutch specific titlecasing with "IJ" characters + // Special case to check for Dutch specific titlecasing with "IJ" characters // at the beginning of a word if (isDutchCulture && i < str.Length - 1 && (str[i] == 'i' || str[i] == 'I') && (str[i+1] == 'j' || str[i+1] == 'J')) { @@ -740,17 +663,14 @@ namespace System.Globalization i = AddTitlecaseLetter(ref result, ref str, i, charLen) + 1; } - // // Convert the characters until the end of the this word // to lowercase. - // int lowercaseStart = i; - // // Use hasLowerCase flag to prevent from lowercasing acronyms (like "URT", "USA", etc) // This is in line with Word 2000 behavior of titlecasing. - // bool hasLowerCase = (charType == UnicodeCategory.LowercaseLetter); + // Use a loop to find all of the other letters following this letter. while (i < str.Length) { @@ -867,7 +787,6 @@ namespace System.Globalization { switch (input[inputIndex]) { - // // For AppCompat, the Titlecase Case Mapping data from NDP 2.0 is used below. case (char) 0x01C4: // DZ with Caron -> Dz with Caron case (char) 0x01C5: // Dz with Caron -> Dz with Caron @@ -897,12 +816,10 @@ namespace System.Globalization return inputIndex; } - // // Used in ToTitleCase(): // When we find a starting letter, the following array decides if a category should be // considered as word seprator or not. - // - private const int c_wordSeparatorMask = + private const int c_wordSeparatorMask = /* false */ (0 << 0) | // UppercaseLetter = 0, /* false */ (0 << 1) | // LowercaseLetter = 1, /* false */ (0 << 2) | // TitlecaseLetter = 2, @@ -933,8 +850,8 @@ namespace System.Globalization /* true */ (1 << 27) | // ModifierSymbol = 27, /* true */ (1 << 28) | // OtherSymbol = 28, /* false */ (0 << 29); // OtherNotAssigned = 29; - - private static bool IsWordSeparator(UnicodeCategory category) + + private static bool IsWordSeparator(UnicodeCategory category) { return (c_wordSeparatorMask & (1 << (int) category)) != 0; } diff --git a/src/System.Private.CoreLib/shared/System/Number.Formatting.cs b/src/System.Private.CoreLib/shared/System/Number.Formatting.cs index aa6d69f..1ae5b65 100644 --- a/src/System.Private.CoreLib/shared/System/Number.Formatting.cs +++ b/src/System.Private.CoreLib/shared/System/Number.Formatting.cs @@ -1908,7 +1908,7 @@ namespace System // The max is not bound since you can have formatting strings of the form "000,000..", and this // should handle that case too. - int[] groupDigits = info.numberGroupSizes; + int[] groupDigits = info._numberGroupSizes; int groupSizeIndex = 0; // Index into the groupDigits array. int groupTotalSizeCount = 0; @@ -2116,7 +2116,7 @@ namespace System switch (ch) { case '#': - FormatFixed(ref sb, ref number, nMaxDigits, info, info.currencyGroupSizes, info.CurrencyDecimalSeparator, info.CurrencyGroupSeparator); + FormatFixed(ref sb, ref number, nMaxDigits, info, info._currencyGroupSizes, info.CurrencyDecimalSeparator, info.CurrencyGroupSeparator); break; case '-': sb.Append(info.NegativeSign); @@ -2244,7 +2244,7 @@ namespace System switch (ch) { case '#': - FormatFixed(ref sb, ref number, nMaxDigits, info, info.numberGroupSizes, info.NumberDecimalSeparator, info.NumberGroupSeparator); + FormatFixed(ref sb, ref number, nMaxDigits, info, info._numberGroupSizes, info.NumberDecimalSeparator, info.NumberGroupSeparator); break; case '-': sb.Append(info.NegativeSign); @@ -2351,7 +2351,7 @@ namespace System switch (ch) { case '#': - FormatFixed(ref sb, ref number, nMaxDigits, info, info.percentGroupSizes, info.PercentDecimalSeparator, info.PercentGroupSeparator); + FormatFixed(ref sb, ref number, nMaxDigits, info, info._percentGroupSizes, info.PercentDecimalSeparator, info.PercentGroupSeparator); break; case '-': sb.Append(info.NegativeSign); diff --git a/src/System.Private.CoreLib/shared/System/Number.Parsing.cs b/src/System.Private.CoreLib/shared/System/Number.Parsing.cs index 89ae0a9..37facda 100644 --- a/src/System.Private.CoreLib/shared/System/Number.Parsing.cs +++ b/src/System.Private.CoreLib/shared/System/Number.Parsing.cs @@ -398,11 +398,11 @@ namespace System { char* temp = p; ch = ++p < strEnd ? *p : '\0'; - if ((next = MatchChars(p, strEnd, info.positiveSign)) != null) + if ((next = MatchChars(p, strEnd, info._positiveSign)) != null) { ch = (p = next) < strEnd ? *p : '\0'; } - else if ((next = MatchChars(p, strEnd, info.negativeSign)) != null) + else if ((next = MatchChars(p, strEnd, info._negativeSign)) != null) { ch = (p = next) < strEnd ? *p : '\0'; negExp = true; diff --git a/tests/CoreFX/CoreFX.issues.json b/tests/CoreFX/CoreFX.issues.json index 957a86f..4489b51 100644 --- a/tests/CoreFX/CoreFX.issues.json +++ b/tests/CoreFX/CoreFX.issues.json @@ -23,6 +23,118 @@ { "name": "System.Globalization.Tests.CharUnicodeInfoGetUnicodeCategoryTests.GetUnicodeCategory", "reason": "We updated the Unicode data and didn't pick yet the updated tests from corefx. we should remove this entry after updating the tests in coreclr." + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoNegativeInfinitySymbol.NegativeInfinitySymbol_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoPercentDecimalDigits.PercentDecimalDigits_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoCurrencyGroupSeparator.CurrencyGroupSeparator_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoNumberNegativePattern.NumberNegativePattern_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoPositiveInfinitySymbol.PositiveInfinitySymbol_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.StringInfoString.String_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoNumberDecimalSeparator.NumberDecimalSeparator_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoNumberGroupSeparator.NumberGroupSeparator_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoNaNSymbol.NaNSymbol_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoPositiveSign.PositiveSign_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoCurrencyGroupSizes.CurrencyGroupSizes_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoPercentSymbol.PercentSymbol_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.StringInfoCtorTests.Ctor_String_Null_ThrowsArgumentNullException", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoCurrencySymbol.CurrencySymbol_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoPercentDecimalSeparator.PercentDecimalSeparator_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.DateTimeFormatInfoGetAbbreviatedDayName.GetAbbreviatedDayName_Invalid_ThrowsArgumentOutOfRangeException", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoNumberDecimalDigits.NumberDecimalDigits_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoNegativeSign.NegativeSign_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoPercentGroupSizes.PercentGroupSizes_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoNumberGroupSizes.NumberGroupSizes_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoPercentPositivePattern.PercentPositivePattern_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoPerMilleSymbol.PerMilleSymbol_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoPercentGroupSeparator.PercentGroupSeparator_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoCurrencyNegativePattern.CurrencyNegativePattern_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoCurrencyPositivePattern.CurrencyPositivePattern_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoPercentNegativePattern.PercentNegativePattern_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoCurrencyDecimalDigits.CurrencyDecimalDigits_Set_Invalid", + "reason": "outdated" + }, + { + "name": "System.Globalization.Tests.NumberFormatInfoCurrencyDecimalSeparator.CurrencyDecimalSeparator_Set_Invalid", + "reason": "outdated" } ] }