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 はスタックに置かれ、 に変換されますint64が、 unsigned から signed への追加の変換はありません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)

オーバーフローの場合に必要な unsigned から signed へのキャストがあります。

残念ながら、これは元の質問には答えません。

更新:回答の間違った部分を削除したため、実際の回答は残りません。ただし、役立つと思うので、回答全体を削除していません。

于 2013-04-02T16:39:53.273 に答える
2

IntPtrおよびタイプは、それ自体が数値であるアドレスのUIntPtr単なる管理された表現です。したがって、論理的に数値であり、同じ符号付き/符号なしの値の間の変換を提供します。

この場合UIntPtr、 は符号なしであるため、 のような符号なし数値への変換のみを提供しますulong。これは、 (符号付き) 値 Aを受け入れる明示的な演算子とは互換性がありません。long

追加の演算子を追加するか、fromulongに明示的にキャストする必要がありますlongUIntPtr

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