Подтвердить что ты не робот

Почему явный приведение к "десятичному вызову явного оператора" длинный "?

Рассмотрим следующий код:

class Program
{
    public static explicit operator long(Program x) { return 47; }

    static int Main(string[] args)
    {
        var x = new Program();
        Console.WriteLine((decimal) x);
    }
}

К моему удивлению, это выводит 47; Другими словами, explicit operator long вызывается, даже если приведение равно decimal.

Есть ли что-то в спецификации С#, которая явно говорит, что это должно произойти (если да, где именно) или это результат какого-либо другого правила (ов) Im missing?

4b9b3361

Ответ 1

Я нашел ответ. Прежде всего, понятие одного типа включено другим, которое определено в 6.4.3. Оценка пользовательских преобразований следующим образом:

Если стандартное неявное преобразование (§6.3.1) существует от типа A до тип B, и если ни A, ни B не являются типами интерфейсов, то A называется охватывается B, а B называется охватывать A.

6.3.1 Стандартные неявные преобразования указывают, что "Неявные числовые преобразования (§6.1.2)" являются стандартным неявным преобразованием и 6.1.2. Неявные числовые преобразования в свою очередь определяют неявное преобразование от long до decimal. Следовательно, long охватывает decimal.

Далее, 6.4.5. Явные преобразования, определяемые пользователем, указывают, что одним из этапов определения, применимо ли явное преобразование, является:

Найти набор применимых пользовательских и отмененных преобразований операторов, U. Это множество состоит из определяемого пользователем и снятого неявные или явные операторы преобразования, объявленные классами или структур в D, которые преобразуются из типа, охватывающего или охватываемого S к типу, охватывающему или охватываемому Т. Если U пусто, преобразование undefined и возникает ошибка времени компиляции.

Здесь D относится к результату более раннего шага, который в этом случае содержит только decimal, Program и object. Таким образом, набор U будет содержать явный оператор Program -to-long, который я объявил, потому что long включен decimal (как мы обнаружили ранее).

Один из следующих шагов выбирает long как наиболее специфический целевой тип, TX.

Наконец, последний шаг в том же алгоритме гласит:

Наконец, примените преобразование:

  • Если S не SX, то выполняется стандартное явное преобразование из S в SX.
  • Вызывается наиболее конкретный пользовательский оператор преобразования для преобразования из SX в TX.
  • Если TX не является T, выполняется стандартное явное преобразование из TX в T.

Здесь S и SX являются Program, поэтому первая часть ничего не делает. TX был выбран как long, а T - целевой тип decimal, поэтому последняя часть выполняет стандартное преобразование от long до decimal.

Ответ 2

Единственное объяснение, о котором я могу думать, заключается в том, что компилятор достаточно умен, чтобы понять, что существует неявный оператор, который будет преобразовывать long в десятичный, что он может использовать для удовлетворения явного преобразования между Программой и десятичным, когда Программа может преобразовывать только долго.

EDIT: Здесь мы находимся; конверсии между числовыми типами встроены в спецификацию языка:

6.1.2 Неявные числовые преобразования

Неявные числовые преобразования:

. От sbyte до short, int, long, float, double или decimal.

От байта до короткого, ushort, int, uint, long, ulong, float, двойным или десятичным.

· От short до int, long, float, double или decimal.

. От ushort до int, uint, long, ulong, float, double или десятичное.

. От int до long, float, double или decimal.

· От uint до long, ulong, float, double или decimal.

· От длинного до плавающего, двойного или десятичного.

. От ulong до float, double или decimal.

. От char до ushort, int, uint, long, ulong, float, double, или десятичной.

. От float до double.

Конверсии из int, uint, long или ulong для float и из long или Улунг удваивается, может привести к потере точности, но никогда не вызовет потери величины. Другие неявные числовые преобразования никогда не теряются любая информация.

Нет никаких неявных преобразований в тип char, поэтому значения другие интегральные типы автоматически не преобразуются в тип char.

Таким образом, при преобразовании между программой и десятичной точкой С# знает, что он может неявно преобразовывать из любого числового типа в десятичный, поэтому при выполнении этого явного преобразования он будет искать любой оператор, который может получить Программу для числового типа.

Что было бы интересно увидеть, что произойдет, если вы также внесете явное преобразование в, скажем, uint, который вернул 48? Какой из них выбрать компилятор?