过程
平时候我们声明一个整数,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