为什么这个断言失败了?
Assert.AreEqual( Color.Red, Color.FromArgb( Color.Red.A, Color.Red.R, Color.Red.G, Color.Red.B ) );
以下是颜色比较的实现方式:
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;
}
工作原理:
value
。它是当前实例的 ARGB 值(存储在一个 long
类型的字段中)。因此,如果 ARGB 不同,则颜色不同。这一步你已经成功通过。state
。它显示了颜色是如何创建的:从 ARGB、从 KnownColor 还是通过名称。 实际上,你在这一步比较失败了。knownColor
。它具有 KnownColor 枚举的值,或者如果颜色不是从已知颜色创建的,则为零。name
。除了用名称创建的颜色外,它的值为 null
。因此,如果要比较颜色的值,应该使用比较中的 value
字段(它由 ToArgb 方法返回):
Assert.AreEqual(color1.ToArgb(), color2.ToArgb());
编辑
要创建某种颜色的副本,您可以使用以下扩展方法:
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());
}
现在断言通过:
Assert.AreEqual(Color.Red, Color.Red.Copy());
但这没有意义,因为你可以在程序的任何地方使用单个颜色实例 :)
Color.Red
是一个命名颜色,而 Color.FromArgb(...)
不是。因此,即使它们具有相同的 ARGB 值,它们也不被认为是相等的。请注意,它们的字符串表示形式也不同:
Color.Red.ToString() : "Color [Red]"
Color.FromArgb(...).ToString() : "Color [A=255, R=255, G=0, B=0]"
Color
类的Equals
重写会检查两种颜色是否为已命名(已知)颜色:
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;
}
由于颜色是一个结构体,除了ARGB值之外,它还具有许多其他属性。例如,如果您使用两种不同的方法创建颜色,则它们将具有不同的名称,因此它们将不相等。
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
结构体本身没有任何相等逻辑(即如果要使用“==”)。因此,对于每个结构体,都必须定义此运算符。如果您调查颜色,您将看到“==”运算符的以下定义。它取决于如何实现此运算符。
// 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);
// 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);
Color b = Color.FromArgb(a.A, a.R, a.G, a.B);
的情况下,名称将为 null
。 - Sergey BerezovskiyName
只有在实际上没有字符串时才会生成一个。我指出这一点,因为在比较中并没有使用属性Name
,而只使用了实际字段name
。 - Sergey BerezovskiySystem.Drawing.Color
结构的实现方式所导致的。它拥有一个单独的Name
属性,对于Color.Red
来说是"Red",但当你从Color.Red
创建自己的Color
时,Name
会变得不同。而System.Windows.Media.Color
(即WPF的Color
实现)则没有这个问题。