Как С# знает, какой тип литерала?
Рассмотрим этот код:
double i = 0xF0000000;
Console.WriteLine(0xF0000000.GetType());
Console.WriteLine(i.GetType());
Почему С# печатает System.UInt32
для первого и System.Double
для второго?
Это потому, что компилятор по умолчанию выводит литерал типа var
?
Ответы
Ответ 1
В этой строке:
double i = 0xF0000000;
литерал имеет тип uint
, но он неявно преобразован в double
. Когда вы вызываете i.GetType()
, который всегда печатает System.Double
, потому что переменная имеет тип double
... единственным типом значения, которое она может удерживать, является double
.
Обратите внимание, что это преобразование в double
означает, что вы можете потерять точность, если вы начинаете с long
или ulong
. Например:
using System;
public class Program
{
static void Main()
{
long x = 123456789012345678;
double y = 123456789012345678;
Console.WriteLine(x.ToString("n"));
Console.WriteLine(y.ToString("n"));
}
}
печатает
123,456,789,012,345,678.00
123,456,789,012,346,000.00
Обратите внимание на то, что последние несколько цифр теряются в double
, потому что неявное преобразование от long
до double
может потерять точность. (Оба имеют 64 бита, но в double
только некоторые из этих бит используются для мантиссы.)
Это не проблема для литералов int
или uint
, но стоит знать, что происходит преобразование.
Ответ 2
Согласно Integer Literals (С#) тип целочисленного литерала зависит от значения и его суффикса.
- Если литерал не имеет суффикса, он имеет первый из этих типов, в котором его значение может быть представлено: int, uint, long, ulong.
- Если литерал суффикс U или u, он имеет первый из этих типов, в котором его значение может быть представлено: uint, ulong.
- Если литерал суффикс L или l, он имеет первый из этих типов, в котором его значение может быть представлено: long, ulong.
- Если литерал суффикс UL, Ul, uL, ul, LU, Lu, lU или lu, он имеет тип ulong.
0xF0000000 не имеет суффикса, поэтому он соответствует первому типу (int, uint, long, ulong)
- int 32-битная подпись: 0xF0000000 находится за пределами диапазона для положительных значений - Next...
- uint 32-разрядный без знака: 0xF0000000 находится в пределах диапазона - ОК.
Итак, 0xF0000000 имеет тип uint.
decimal x = 0xF00000000;
Здесь x - десятичная переменная. Когда вы присваиваете ему значение uint, это значение неявно преобразуется в десятичное (поэтому оно будет вписываться в десятичную переменную).