编译器取代了明确的投我自己的类型有明确的转换到.NET类型? [英] Compiler replaces explicit cast to my own type with explicit cast to .NET type?
问题描述
我有以下代码:
公共结构民< T>
{
私人只读牛逼_Value;
公民(T值)
{
_Value =价值;
}
静态公共明确运营商民< T>(T值)
{
返回新的民< T>(值);
}
}
...
双D = 2.5;
&民LT;字节> B =(民<位>)D;
这代码编译,而且我的惊喜。显式转换应该只接受字节
,而不是双击
。但双莫名其妙地接受。当我把一个断点转换里面,我看到值
已经是字节
值为 2
。 。通过从双转换为字节应该是明确的。
如果我编译我的EXE与ILSpy,我看到了下面的代码:
双D = 2.5;
Program.Num<位> B =(字节)D;
我的问题是:哪里是额外的强制转换为字节
来自何处?这是为什么额外投的地方吗?我投在哪里做,以民<字节>
到
修改
的结构民< T>
是完整的结构,所以没有更多的隐藏额外的方法或运营商
。
修改结果
的IL,按要求:
IL_0000: NOP
IL_0001:ldc.r8 2.5 //将双2.5。
IL_000a:stloc.0
IL_000b:ldloc.0
IL_000c:// conv.u1再次明确强制转换为字节。
IL_000d:调用值类型GeneriCalculator.Program / Num`1℃的>值类型GeneriCalculator.Program / Num`1<&UINT8 GT; :: op_Explicit(0!)
IL_0012:stloc.1
IL_0013:RET
让我们退后一步,问了一些澄清的问题:
这是程序合法。
块引用>
公共结构民< T>
{
私人只读牛逼_Value;
公民(T值)
{
_Value =价值;
}
静态公共明确运营商民< T>(T值)
{
返回新的民< T>(值);
}
}
类节目
{
静态无效的主要()
{
双D = 2.5;
&民LT;字节> B =(民<位>)D;
}
}
是
你能解释为什么演员是合法的吗?
块引用>
肯健指出, ,我解释说,在这里:
简单地说:一个用户定义的显式转换可能会在插入两端内置的显示转换。也就是说,我们可以插入一个显式转换无论是从源表达的参数类型的用户定义转换方法的,或者从用户定义的转换方法转换的目标类型的返回类型。 (或者,在某些罕见的情况下,无论是。)
在这种情况下,我们插入一个内置的显式转换参数类型,字节,所以你的程序是一样的因为如果你会写:
民<位> B =(民<位>)(字节)D;
这是可取的行为。双可能被显式转换为字节,所以双也可以显式转换为
民<位>
。
有关完整的说明,请阅读6.4.5节中的C#4规范的用户自定义显式转换。
为什么白细胞介素生成调用
op_Implicit
而不是op_Explicit
?
块引用>
它没有;这个问题的前提是一个谎言。以上程序生成:
IL_0000:NOP
IL_0001:ldc.r8 2.5
IL_000a:stloc。 0
IL_000b:ldloc.0
IL_000c:conv.u1
IL_000d:调用值类型Num`1℃的>值类型Num`1<&UINT8 GT; :: op_Explicit(0!)
IL_0012:stloc.1
IL_0013:RET
您正在寻找一个老版本可能是你的计划。做一个干净的重建。
有没有在C#编译器默默插入一个显式转换的其他情况?
块引用>
是的;其实这是第二次这个问题今天已经上来了。见
I have the following code:
public struct Num<T> { private readonly T _Value; public Num(T value) { _Value = value; } static public explicit operator Num<T>(T value) { return new Num<T>(value); } } ... double d = 2.5; Num<byte> b = (Num<byte>)d;
This code compiles, and it surprises my. The explicit convert should only accept a
byte
, not adouble
. But the double is accepted somehow. When I place a breakpoint inside the convert, I see thatvalue
is already abyte
with value2
. By casting from double to byte should be explicit.If I decompile my EXE with ILSpy, I see the next code:
double d = 2.5; Program.Num<byte> b = (byte)d;
My question is: Where is that extra cast to
byte
coming from? Why is that extra cast place there? Where did my cast toNum<byte>
go to?EDIT
The structNum<T>
is the entire struct, so no more hidden extra methods or operators.EDIT
The IL, as requested:IL_0000: nop IL_0001: ldc.r8 2.5 // Load the double 2.5. IL_000a: stloc.0 IL_000b: ldloc.0 IL_000c: conv.u1 // Once again the explicit cast to byte. IL_000d: call valuetype GeneriCalculator.Program/Num`1<!0> valuetype GeneriCalculator.Program/Num`1<uint8>::op_Explicit(!0) IL_0012: stloc.1 IL_0013: ret
解决方案Let's take a step back and ask some clarifying questions:
Is this program legal?
public struct Num<T> { private readonly T _Value; public Num(T value) { _Value = value; } static public explicit operator Num<T>(T value) { return new Num<T>(value); } } class Program { static void Main() { double d = 2.5; Num<byte> b = (Num<byte>)d; } }
Yes.
Can you explain why the cast is legal?
As Ken Kin pointed out, I explain that here:
Briefly: a user-defined explicit conversion may have a built-in explicit conversion inserted on "both ends". That is, we can insert an explicit conversion either from the source expression to the parameter type of the user-defined conversion method, or from the return type of the user-defined conversion method to the target type of the conversion. (Or, in some rare cases, both.)
In this case we insert a built-in explicit conversion to the parameter type, byte, so your program is the same as if you'd written:
Num<byte> b = (Num<byte>)(byte)d;
This is desirable behaviour. A double may be explicitly converted to byte, so a double may also be explicitly converted to
Num<byte>
.For a complete explanation, read section 6.4.5 "User-defined explicit conversions" in the C# 4 specification.
Why does the IL generated call
op_Implicit
instead ofop_Explicit
?It doesn't; the question is predicated on a falsehood. The above program generates:
IL_0000: nop IL_0001: ldc.r8 2.5 IL_000a: stloc.0 IL_000b: ldloc.0 IL_000c: conv.u1 IL_000d: call valuetype Num`1<!0> valuetype Num`1<uint8>::op_Explicit(!0) IL_0012: stloc.1 IL_0013: ret
You're looking at an old version of your program probably. Do a clean rebuild.
Are there other situations in which the C# compiler silently inserts an explicit conversion?
Yes; in fact this is the second time that question has come up today. See
C# type conversion inconsistent?
这篇关于编译器取代了明确的投我自己的类型有明确的转换到.NET类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!