LoginSignup
1
0

More than 5 years have passed since last update.

Color.Black == (new Pen(Brushes.Black)).Colorの結果がFalseになる

Last updated at Posted at 2016-05-02

前提

以下の環境で確認してます
- .Net Framework 4.6.2
- Visual Studio 2015

現象

PenオブジェクトのColorが黒か否かによって、処理を分岐するコードを書いたけどうまく動かない。
Brushes.Blackから生成したpenオブジェクトなのに、下のコードを実行してもBの処理に行ってしまう。。

program.cs

            Pen pen = new Pen(Brushes.Black);
            if (pen.Color == Color.Black)
            {
                // Aの処理
            }
            else
            {
                // Bの処理
            }

原因

Colorクラス内の operator ==の処理で、
Color.value, state,knownColor,name全てが一致していないとtrueが返らないが、
今回の場合全てが一致しないため。

実はColor.Black == Color.FromArgb(255, 0, 0, 0)の戻り値もFalseになる。
比較を行う際には、回避策の方法でチェックするのが王道なのかも。
ARGBがあっていればTrueで値が返ってもいいと思うんだけど。。

回避法

とりあえず黒だったらA, そうでなければBの分岐に行けばよかったので、Color.ToArgbメソッドでARGBの値に直してチェックしてみてる。
戻り値がintなので、結局上位ビットが切り捨てられて比較が成功してるぽい。

program.cs

            Pen pen = new Pen(Brushes.Black);
            if (pen.Color.ToArgb() == Color.Black.ToArgb())
            {
                // Aの処理
            }
            else
            {
                // Bの処理
            }

蛇足

Color.Valueの値を確認していると、
Color.Black.Valueは0xffffffffff000000で
Pen.Color.Valueは0x00000000FF000000。
上位32bitの差は何なの?

両方とも元のARGB値はint 0xFF000000だけど、
.Netのソースを追っていくと
Colorの方はint → longにキャスト
Penの方はintの値をlongにキャストして、0xffffffffの論理積をとってる。

Penの処理の理由はわからないけど、戻り値が0x00000000FF000000になるのはまあわかる。
Colorの方はなんで上位ビットに1が立つのか?を見ていくと、符号拡張なるものが原因みたい。

6.2.1 明示的な数値変換 (C#)

変換元の型が変換先の型より小さい場合は、変換先の型と同じサイズになるように、変換前の値に対して符号拡張またはゼロ拡張が行われます。
変換元の型が符号付きの場合は符号拡張が使われて、符号なしの場合はゼロ拡張が使われます。その後、結果は変換先の型の値として扱われます。

0xFF000000は最上位ビットが1なので符号はマイナス。
なのでint→longへの数値変換時に上位ビットが1で埋められている。

なんで上位ビットを1で埋めるかと言ったら、絶対値を求めるために補数を計算するときに上位桁が0じゃないとおかしくなるから。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0