Reputation: 9581
Why does this assertion fail?
Assert.AreEqual( Color.Red, Color.FromArgb( Color.Red.A, Color.Red.R, Color.Red.G, Color.Red.B ) );
Upvotes: 10
Views: 5365
Reputation: 236308
Here is how Colors comparison implemented:
public override bool Equals(object obj)
{
if (obj is Color)
{
Color color = (Color) obj;
if ((this.value == color.value)
&& (this.state == color.state)
&& (this.knownColor == color.knownColor))
{
return ((this.name == color.name)
|| ((this.name != null)
&& (color.name != null)
&& this.name.Equals(color.name)));
}
}
return false;
}
How it works:
value
compared. It is Argb values of current instance (they are stored in one field of type long
). So, if Argb different, we have different colors. You pass this step successfully.state
compared. It shows the way how color was created: from Argb, from KnownColor, or by name. Actually your comparison fails on this step.knownColor
compared. It has value of KnownColor enum, or zero, if color was not created from known color.name
compared. It has null
value for all colors except ones created by name.So, if you want to compare values of colors, you should use value
field in comparison (it is returned by ToArgb method):
Assert.AreEqual(color1.ToArgb(), color2.ToArgb());
Edit
To create copy of some color you can use following extension method:
public static class ColorHelper
{
public static Color Copy(this Color color)
{
if (color.IsKnownColor)
return Color.FromKnownColor(color.ToKnownColor());
if (color.IsNamedColor)
return Color.FromName(color.Name);
// this is better, then pass A,r,g,b separately
return Color.FromArgb(color.ToArgb());
}
Now assertion passes:
Assert.AreEqual(Color.Red, Color.Red.Copy());
But it makes no sense, because you can use single color instance in every place of your program :)
Upvotes: 12
Reputation: 14929
Since Color is a struct, it has many properties other than just ARGB values. For instance, if you create a color using two different approaches, they will have different names; thus they will not be equal.
Color a = Color.Red;
Color b = Color.FromArgb(a.A, a.R, a.G, a.B);
string name1 = a.Name; //name is Red
string name2 = b.Name; //name is ffff0000
Structs do not have any equality logic by themselves(i.e. if you want to use '==').Thus for every struct, this operator shall be defined. If you investigate Color, you will see the following definition of '==' operator. It depends on how this operator is implemented.
// Summary:
// Tests whether two specified System.Drawing.Color structures are equivalent.
//
// Parameters:
// left:
// The System.Drawing.Color that is to the left of the equality operator.
//
// right:
// The System.Drawing.Color that is to the right of the equality operator.
//
// Returns:
// true if the two System.Drawing.Color structures are equal; otherwise, false.
public static bool operator ==(Color left, Color right);
Also 'Equals' is overriden in the struct such that it checks for equivalence of structs;
// Summary:
// Tests whether the specified object is a System.Drawing.Color structure and
// is equivalent to this System.Drawing.Color structure.
//
// Parameters:
// obj:
// The object to test.
//
// Returns:
// true if obj is a System.Drawing.Color structure equivalent to this System.Drawing.Color
// structure; otherwise, false.
public override bool Equals(object obj);
Upvotes: 2
Reputation: 178810
This is a consequence of the way the System.Drawing.Color
structure is implemented. It has a separate Name
property, which is "Red" for Color.Red
but is different when you create your own Color
from Color.Red
. System.Windows.Media.Color
(ie. WPF's Color
implementation) does not exhibit this same problem.
Upvotes: 2
Reputation: 4242
The Equals
override of the Color
class checks, whether both colors are named (known) colors or not:
public override bool Equals(object obj)
{
if (obj is Color)
{
Color color = (Color) obj;
if (((this.value == color.value) && (this.state == color.state)) && (this.knownColor == color.knownColor))
{
return ((this.name == color.name) || (((this.name != null) && (color.name != null)) && this.name.Equals(this.name)));
}
}
return false;
}
Upvotes: 2
Reputation: 292705
Color.Red
is a named color, while Color.FromArgb(...)
is not. So they're not considered equal, even though they have the same ARGB values. Note that the string representation is also different:
Color.Red.ToString() : "Color [Red]"
Color.FromArgb(...).ToString() : "Color [A=255, R=255, G=0, B=0]"
Upvotes: 2