2012-03-05 10 views
3

ulongの周りに簡単なラッパーを作成しました。ラッパーをulongにキャストしてデータを取得できるようにしたい。 uintにキャストしてデータを失うのは違法であるため、uintへの明示的なキャストは書きませんでした。あなたはC#が私にuintにキャストすることを許可し、高いビットが失われても例外をスローしなかったときに私の驚きを想像することができます。そのような演算子がない場合、uintへの明示的キャスト

class Program { 
    static void Main(string[] args) { 
     ULongWrapper a = new ULongWrapper(0xfffffffffUL); 
     ulong b = (ulong)a; 
     uint c = (uint)a; 
     Console.WriteLine("{0:x}", b); 
     Console.WriteLine("{0:x}", c); 
    } 
} 
class ULongWrapper { 
    private ulong data; 
    public ULongWrapper(ulong data) { 
     this.data = data; 
    } 
    public static explicit operator ulong(ULongWrapper x) { 
     return x.data; 
    } 
} 

出力します:

は、ここに私のテストコードです

私はコンパイル時に失敗する uintにキャストしたいので、これは、不要な行動のように思える
fffffffff 
ffffffff 

!コンパイラはulong明示的キャスト演算子を使用していて、境界チェックなしで暗黙的にその結果をuintにキャストしています。これはC#のバグですか?もしそうでなければ、なぜですか?

+0

'int d =(int)a'はエラーを生成します。CS0030: 'TestProgram.ULongWrapper'を 'int'に変換できません。しかし、 'int d =(int)b'は動作します。 – Zach

+0

クラスからuintへの明示的な変換を定義し、変換メソッドで例外をスローする方法はありますか? – phoog

答えて

13

これはC#のバグですか?

なぜいけないのでしょうか?

ここで示した動作は仕様と一致しているためです。仕様のセクション6.4.4と6.4.5を注意深く読んでください。私はそれがしたい

;(実装は、特に持ち上げた演算子を含む、あいまいなコーナーケースのバグの数を持っています。仕様のこの部分と一致していないC#コンパイラには多くの方法があることに注意してください) uintにキャストしてデータを失うことは違法です。

残念ながら、あなたが望むものを得ることはできません。

C#で苦情なしで私がuintにキャストすることを許可し、高いビットが失われても例外をスローしなかったと思います。

これは少し驚くべきことですが、私は同意します。

規則がある:すべてのユーザ定義の変換は、入力出力両方に挿入標準変換を持たせることができます。さらに、明示的変換の場合、すなわちキャストを実行している場合、挿入される標準の変換は暗黙のうちにまたは明示的標準変換のいずれかになります。 (実際には、キャストによって明示的な標準変換がユーザー定義の暗黙的変換に挿入される可能性があります)。

ULongWrapperからulongへの明示的なユーザー定義変換があります。 uint to uint。したがって、ULongWrapperをuintにキャストすることは合法です。

明らかに明示的な変換のセマンティクスが気に入らないため、最初は明示的な変換を実装しない方がよいかもしれません。基本的なulongを返すメソッドまたはプロパティを記述して、それを使って終了してください。

+0

+1、私のコメントの説明について私のラウンドよりもはるかに優れています。 –

+2

それではなぜ 'int d =(int)a'を実行できないのですか?(エラーCS0030を生成します: 'TestProgram.ULongWrapper'を 'int'に変換できません)? – Zach

+0

@Zach:しかし、あなたはこれを行うことができます: 'int x =(int)(ulong)a;'。それは面白いです... –

1

キャスト中にオーバーフローが発生しますが、オーバーフローチェックはC#で「オプトイン」です。 でキャストをラップ:はなく、バグ「デザインによって」その本当にそう

checked 
{ 
    .. 
} 

。そして、ulongを返すことは、私が考えるコンパイル時に常にキャスタブルになります。

+0

これは実行時のチェックであり、コンパイル時のチェックではありません。私は解決策を知っているわけではない...ちょうど言っている。 –

+0

'チェック{ パブリック静的明示的演算子ulong(ULongWrapper x){ return x.data; }} ' CS1519の結果:クラス、構造体、またはインターフェイスメンバの宣言で無効なトークンが 'checked'になりました。 – Zach

+0

また、Edが言っているように、これは実行時にチェックされ、 'public static explicit operator uint(ULongWrapper x){throw new OverflowException();}' – Zach

2

uintulongの間に明示的な変換が存在します。 ulongに変換することができます。は、uintに明示的にキャストします。あなたは何を期待していますか?あなたはコンパイラに "それについて心配しないで、私がやっていることを知っている"と言っています。

、その後、何らかの形で暗黙的にそれについての暗黙的なものは何もありませんUINT

にその結果をキャスト。あなたはキャストを行っています。これは過度に防御的なプログラミングのようです。

+0

私は暗黙的に 'ulong'への変換を許可していません。実際に明示的な変換チェーンは '(uint)(ulong)a'です。これは不平を伴わずに切り詰めるべきです(そしてそうする)。 – Zach

+0

@ Zach:なぜそれが混乱しているように見えますが、コンパイラは 'ulong'への明示的な変換を定義していることが分かります。もし 'ulong'に変換でき、' uint'への明示的な変換が有効であれば、式全体が有効です。したがって、事実上、あなたはそれを許します。 –

関連する問題