C# Int ToString 方法原理

过程

平时候我们声明一个整数,ToString的时候是发生什么了呢
在这里插入图片描述

1 调用

使用示例,声明整数a,b

    static void Main(string[] args)
    {
        int a = 10;
        int b = -10;

        System.Diagnostics.Debug.WriteLine(a.ToString());
        System.Diagnostics.Debug.WriteLine(b.ToString());
    }

2 ToString方法

int是结构Int32,当整型在ToString的时候其实是调用Int32.ToString方法,整数值是存在字段m_value中。
路径:src\libraries\System.Private.CoreLib\src\System\Int32.cs

namespace System
{
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
    public readonly struct Int32 : IComparable, IConvertible, IFormattable, IComparable<int>, IEquatable<int>, ISpanFormattable
    {
        private readonly int m_value; // Do not rename (binary serialization)

        public const int MaxValue = 0x7fffffff;
        public const int MinValue = unchecked((int)0x80000000);

        //...

        public override string ToString()
        {
            return Number.Int32ToDecStr(m_value);
        }
    }
}

3 Int32ToDecStr方法

大多数数字处理都在分布类Number中,其中文件Number.Formatting.cs主要包含数字格式转换。当数字是负数时,先把数字转为正整数处理,然后在字符串前添加‘-’
路径:src\libraries\System.Private.CoreLib\src\System\Number.Formatting.cs

    public static string Int32ToDecStr(int value)
    {
        return value >= 0 ?
            UInt32ToDecStr((uint)value) :
            NegativeInt32ToDecStr(value, -1, NumberFormatInfo.CurrentInfo.NegativeSign);
    }

4 UInt32ToDecStr方法

整数转换,如果是个位数从数组里面直接读取。

    private static readonly string[] s_singleDigitStringCache = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };

    internal static unsafe string UInt32ToDecStr(uint value)
    {
        int bufferLength = FormattingHelpers.CountDigits(value);

        // For single-digit values that are very common, especially 0 and 1, just return cached strings.
        if (bufferLength == 1)
        {
            return s_singleDigitStringCache[value];
        }

        string result = string.FastAllocateString(bufferLength);
        fixed (char* buffer = result)
        {
            char* p = buffer + bufferLength;
            do
            {
                value = Math.DivRem(value, 10, out uint remainder);
                *(--p) = (char)(remainder + '0');
            }
            while (value != 0);
            Debug.Assert(p == buffer);
        }
        return result;
    }

5 FormattingHelpers.CountDigits方法

读取当前整数的长度
路径:src\libraries\System.Private.CoreLib\src\System\Buffers\Text\FormattingHelpers.CountDigits.cs

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int CountDigits(uint value)
    {
        int digits = 1;
        if (value >= 100000)
        {
            value /= 100000;
            digits += 5;
        }

        if (value < 10)
        {
            // no-op
        }
        else if (value < 100)
        {
            digits++;
        }
        else if (value < 1000)
        {
            digits += 2;
        }
        else if (value < 10000)
        {
            digits += 3;
        }
        else
        {
            Debug.Assert(value < 100000);
            digits += 4;
        }

        return digits;
    }

6 Math.DivRem方法

获取个位上的数
路径:src\libraries\System.Private.CoreLib\src\System\Math.cs

    internal static uint DivRem(uint a, uint b, out uint result)
    {
        uint div = a / b;
        result = a - (div * b);
        return div;
    }

7. 负数

		public static string Int32ToDecStr(int value)
        {
            return value >= 0 ?
                UInt32ToDecStr((uint)value) :
                NegativeInt32ToDecStr(value, -1, NumberFormatInfo.CurrentInfo.NegativeSign);
        }

Int32ToDecStr 中调用NegativeInt32ToDecStr,其中NumberFormatInfo.CurrentInfo.NegativeSign为负号标记。
src\libraries\System.Private.CoreLib\src\System\Globalization\NumberFormatInfo.cs

    public sealed class NumberFormatInfo : IFormatProvider, ICloneable
    {
    	//...
       internal string _negativeSign = "-";
        //...
         public string NegativeSign
        {
            get => _negativeSign;
            set
            {
                //...
            }
        }
             //...
     }
        //负数处理
        private static unsafe string NegativeInt32ToDecStr(int value, int digits, string sNegative)
        {
            Debug.Assert(value < 0);

            if (digits < 1)
                digits = 1;

            int bufferLength = Math.Max(digits, FormattingHelpers.CountDigits((uint)(-value))) + sNegative.Length;
            string result = string.FastAllocateString(bufferLength);
            fixed (char* buffer = result)
            {
                char* p = UInt32ToDecChars(buffer + bufferLength, (uint)(-value), digits);
                Debug.Assert(p == buffer + sNegative.Length);
				 //负数处理
                for (int i = sNegative.Length - 1; i >= 0; i--)
                {
                    *(--p) = sNegative[i];
                }
                Debug.Assert(p == buffer);
            }
            return result;
        }

8 提供区域性特定的格式

提供区域性特定的格式设置信息的对象,其中N算是用的最多的吧。

// Define cultures whose formatting conventions are to be used.
CultureInfo[] cultures = {CultureInfo.CreateSpecificCulture("en-US"),
                          CultureInfo.CreateSpecificCulture("fr-FR"),
                          CultureInfo.CreateSpecificCulture("es-ES") };
int positiveNumber = 1679;
int negativeNumber = -3045;
string[] specifiers = {"G", "C", "D8", "E2", "F", "N", "P", "X8"};

foreach (string specifier in specifiers)
{
   foreach (CultureInfo culture in cultures)
   {
      // Display values with "G" format specifier.
      Console.WriteLine("{0} format using {1} culture: {2, 16} {3, 16}",
                        specifier, culture.Name,
                        positiveNumber.ToString(specifier, culture),
                        negativeNumber.ToString(specifier, culture));
   }
   Console.WriteLine();
}
// The example displays the following output:
//       G format using en-US culture:             1679            -3045
//       G format using fr-FR culture:             1679            -3045
//       G format using es-ES culture:             1679            -3045
//
//       C format using en-US culture:        $1,679.00      ($3,045.00)
//       C format using fr-FR culture:       1 679,00 €      -3 045,00 €
//       C format using es-ES culture:       1.679,00 €      -3.045,00 €
//
//       D8 format using en-US culture:         00001679        -00003045
//       D8 format using fr-FR culture:         00001679        -00003045
//       D8 format using es-ES culture:         00001679        -00003045
//
//       E2 format using en-US culture:        1.68E+003       -3.05E+003
//       E2 format using fr-FR culture:        1,68E+003       -3,05E+003
//       E2 format using es-ES culture:        1,68E+003       -3,05E+003
//
//       F format using en-US culture:          1679.00         -3045.00
//       F format using fr-FR culture:          1679,00         -3045,00
//       F format using es-ES culture:          1679,00         -3045,00
//
//       N format using en-US culture:         1,679.00        -3,045.00
//       N format using fr-FR culture:         1 679,00        -3 045,00
//       N format using es-ES culture:         1.679,00        -3.045,00
//
//       P format using en-US culture:     167,900.00 %    -304,500.00 %
//       P format using fr-FR culture:     167 900,00 %    -304 500,00 %
//       P format using es-ES culture:     167.900,00 %    -304.500,00 %
//
//       X8 format using en-US culture:         0000068F         FFFFF41B
//       X8 format using fr-FR culture:         0000068F         FFFFF41B
//       X8 format using es-ES culture:         0000068F         FFFFF41B

参考资料
.NetCore源码:https://source.dot.net/#System.Private.CoreLib/Int32.cs,225942ed7b7a3252
官方文档:https://docs.microsoft.com/zh-cn/dotnet/api/system.int32.tostring?view=net-5.0

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:上身试试 返回首页