Почему возможно явного преобразование типа 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)
Т.е. все работает в соответствии со спецификацией.
Комментариев нет:
Отправить комментарий