为什么这个颜色比较失败了?

9

为什么这个断言失败了?

Assert.AreEqual( Color.Red, Color.FromArgb( Color.Red.A, Color.Red.R, Color.Red.G, Color.Red.B ) );

4
请执行以下操作:Color.Red.ToArgb() == Color.FromArgb(255, 0, 0).ToArgb()。 - BlueVoodoo
请查看此处:https://dev59.com/5VvUa4cB1Zd3GeqPtGVF - nawfal
5个回答

11

以下是颜色比较的实现方式:

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;
}

工作原理:

  1. 比较字段 value。它是当前实例的 ARGB 值(存储在一个 long 类型的字段中)。因此,如果 ARGB 不同,则颜色不同。这一步你已经成功通过。
  2. 比较字段 state。它显示了颜色是如何创建的:从 ARGB、从 KnownColor 还是通过名称。 实际上,你在这一步比较失败了。
  3. 比较字段 knownColor。它具有 KnownColor 枚举的值,或者如果颜色不是从已知颜色创建的,则为零。
  4. 比较字段 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());

但这没有意义,因为你可以在程序的任何地方使用单个颜色实例 :)


2

Color.Red 是一个命名颜色,而 Color.FromArgb(...) 不是。因此,即使它们具有相同的 ARGB 值,它们也不被认为是相等的。请注意,它们的字符串表示形式也不同:

Color.Red.ToString()           : "Color [Red]"
Color.FromArgb(...).ToString() : "Color [A=255, R=255, G=0, B=0]"

2
< p > 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;
}

2

由于颜色是一个结构体,除了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);

此外,“Equals” 在该结构中被覆盖,以便检查结构的等价性。
    // 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 Berezovskiy
@lazyberezovsky 你试过这个吗?我已经试过了,它的行为与答案中所述的一样。 - daryal
属性Name只有在实际上没有字符串时才会生成一个。我指出这一点,因为在比较中并没有使用属性Name,而只使用了实际字段name - Sergey Berezovskiy
@lazyberezovsky,我不知道等号或'=='运算符的实现方式,但我想给出关于如何处理两个结构体等价性的一般想法。我该如何查看实现这一点的源代码? - daryal
有一些很棒的工具,比如Reflector或者Telerik的JustDecompile :) - Sergey Berezovskiy

2
这是由于System.Drawing.Color结构的实现方式所导致的。它拥有一个单独的Name属性,对于Color.Red来说是"Red",但当你从Color.Red创建自己的Color时,Name会变得不同。而System.Windows.Media.Color(即WPF的Color实现)则没有这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接