7
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 
4

2 回答 2

3

我同意这看起来有点奇怪,所以我进行了几次测试。

测试#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演员抛出一个OverflowException. 调查这个,我看到我的项目被设置为编译x86,所以现在这个异常是有意义的——Int64.MaxValue太大而不能适应 32 位的IntPtr.

测试#2:checked在相同的代码周围放置一个块。

现在,我真的希望(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 被放入堆栈并转换为 an int64,但没有从 unsigned 到有符号的额外转换int64

checked版本略有不同:

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)

现在有一个从无符号到有符号的转换,这在溢出的情况下是必要的。

不幸的是,这并不能回答最初的问题。

更新:我删除了答案中不正确的部分,因此没有留下任何实际答案。但是,我希望它会有所帮助,因此我没有删除整个答案。

于 2013-04-02T16:39:53.273 回答
2

IntPtrUIntPtr类型只是一个地址的托管表示,它本身就是一个数字。因此,它提供了逻辑数字值和相同有符号/无符号值之间的转换。

在这种情况下UIntPtr是无符号的,因此只提供到无符号数值的转换,如ulong. A这与接受long(有符号)值 的显式运算符不兼容。

您需要为from添加额外的运算符ulong或进行显式转换longUIntPtr

A a = (A)(long)ul;
于 2013-04-02T15:44:12.887 回答