c# – IntPtr允许从ulong到long的隐式转换
class A { public static explicit operator A(long mm) { return null; } } UInt64 ul = UInt64.MaxValue; IntPtr ptr = (IntPtr)ul;//no error A a = (A)ul;//Cannot convert type 'ulong' to 'A' 为什么IntPtr允许这种行为? 以下是IL代码: .entrypoint .maxstack 1 .locals init ( [0] uint64 ul,[1] native int ptr) L_0000: nop L_0001: ldc.i4.m1 L_0002: conv.i8 L_0003: stloc.0 L_0004: ldloc.0 L_0005: call native int [mscorlib]System.IntPtr::op_Explicit(int64) L_000a: stloc.1 L_000b: ret 解决方法
我同意这看起来有点奇怪,所以我进行了几次测试.
测试#1:做一个ulong和long的演员 ulong ul = UInt64.MaxValue; long l = Int64.MaxValue; IntPtr ulptr = (IntPtr)ul; IntPtr lptr = (IntPtr)l; 因为IntPtr转换声明它可能抛出OverflowException,所以我期待(IntPtr)ul强制抛出异常.它没.想象一下,当(IntPtr)l cast抛出一个OverflowException时我会感到惊讶.看看这个,我看到我的项目设置为x86编译,所以异常现在有意义 – Int64.MaxValue太大而不适合32位IntPtr. 测试#2:在相同的代码周围放置一个选中的块. 现在,我真的希望(IntPtr)ul强制抛出异常,它确实如此. 这让我想知道第一次演员是怎么回事.在未经检查的代码上使用ildasm会导致以下结果: IL_0000: nop IL_0001: ldc.i4.m1 IL_0002: conv.i8 IL_0003: stloc.0 IL_0004: ldc.i8 0x7fffffffffffffff IL_000d: stloc.1 IL_000e: ldloc.0 IL_000f: call native int [mscorlib]System.IntPtr::op_Explicit(int64) IL_0014: stloc.2 IL_0015: ldloc.1 IL_0016: call native int [mscorlib]System.IntPtr::op_Explicit(int64) 因此-1被放在堆栈上并转换为int64,但是没有从unsigned到signed int64的额外转换. 选中的版本略有不同: IL_0000: nop IL_0001: nop IL_0002: ldc.i4.m1 IL_0003: conv.i8 IL_0004: stloc.0 IL_0005: ldc.i8 0x7fffffffffffffff IL_000e: stloc.1 IL_000f: ldloc.0 IL_0010: conv.ovf.i8.un IL_0011: call native int [mscorlib]System.IntPtr::op_Explicit(int64) IL_0016: stloc.2 IL_0017: ldloc.1 IL_0018: call native int [mscorlib]System.IntPtr::op_Explicit(int64) 现在有一个从unsigned到signed的转换,这在溢出的情况下是必要的. 不幸的是,这并没有回答原来的问题. 更新:我删除了不正确的答案部分,因此没有留下任何实际答案.但是,我希望它有用,所以我没有删除整个答案. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |