Как С# знает, какой тип литерала?

Рассмотрим этот код:

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, это значение неявно преобразуется в десятичное (поэтому оно будет вписываться в десятичную переменную).