Страницы

Поиск по вопросам

четверг, 4 октября 2018 г.

Почему компилятор C# неявно преобразует double в int при приведении к пользовательскому типу?

Почему возможно явного преобразование типа double в тип foo, хотя в моем типе foo определено только явное преобразование из типа int в тип foo?
Почему в моем случае тип double неявно преобразуется в тип int?
using System;
class Program { static void Main(string[] args) { double doub = 15.7; Foo foo = (Foo)doub; Console.WriteLine(foo.value); //выводит 15 } }
struct Foo { public int value; public static explicit operator Foo(int val) { return new Foo { value = val }; } }


Ответ

Такое поведение определено в спецификации языка в разделе M. Conversions (M. Преобразования). Пункт M.2.8 User-defined explicit conversions
A user-defined explicit conversion consists of an optional standard explicit conversion, followed by execution of a user-defined implicit or explicit conversion operator, followed by another optional standard explicit conversion. The exact rules for evaluating user-defined explicit conversions are described in §User-defined explicit conversion.
И в части пункта M.4.3 Evaluation of user-defined conversions про это тоже говорится:
... Once a most specific user-defined conversion operator has been identified, the actual execution of the user-defined conversion involves up to three steps: First, if required, performing a standard conversion from the source type to the operand type of the user-defined or lifted conversion operator. Next, invoking the user-defined or lifted conversion operator to perform the conversion. Finally, if required, performing a standard conversion from the result type of the user-defined or lifted conversion operator to the target type. ...
Означает, что пользовательское явное преобразование может включать в себя три последовательных преобразований:
Необязательное стандартное явное преобразование. (Исходный тип к типу операнда, в нашем случае это double в int) Пользовательское преобразование неявного или явного оператора. Необязательное стандартное явное преобразование. (Тип результата из 2 пункта к конечному типу. В нашем случае отстуствует этот пункт).
Т.е. можно сказать, что происходит примерно так:
// Пользовательское явное преобразование. Foo foo = (Foo)doub; // Будет вот так. Foo foo = (Foo)(int)doub;
Если глянуть в IL, то увидим там опкод conv.i4 перед вызовом пользовательского приведения.
IL_0000: ldc.r8 15.7 IL_0009: dup IL_000a: conv.i4 IL_000b: call valuetype Foo Foo::op_Explicit(int32)
Т.е. все работает в соответствии со спецификацией.

Комментариев нет:

Отправить комментарий