代码之家  ›  专栏  ›  技术社区  ›  Scott Whitlock

重写等于并与字符串进行比较

  •  4
  • Scott Whitlock  · 技术社区  · 15 年前

    我定义了一个带有字符串成员的C#类。出于所有目的,将此类视为string的子类(不允许的情况除外)。我用它来表示一个与特定格式匹配的强类型字符串字段(我已经大大简化了它)。

    public class field
    {
        private readonly string m_field;
        public field(string init_value)
        {
            //Check the syntax for errors
            if (CheckSyntax(init_value))
            {
                m_field = init_value;
            }
            else
            {
                throw new ArgumentOutOfRangeException();
            }
        }
    
        public override string ToString()
        {
            return m_field;
        }
    }
    

    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }
    
        return this.m_field == obj.ToString();
    }
    
    public override int GetHashCode()
    {
        return this.m_field.GetHashCode();
    }
    
    public static bool operator ==(field x, Object y)
    {
        if ((object)x == null && y == null)
        {
            return true;
        }
        else if ((object)x == null || y == null)
        {
            return false;
        }
        else
        {
            return (x.m_field == y.ToString());
        }
    }
    
    public static bool operator !=(field x, Object y)
    {
        return !(x == y);
    }
    

    现在,当我编写单元测试时,根据我将参数传递给Assert.AreEqual的顺序,我会得到不同的结果:

    string valid = "Some String";
    field target = new field(valid);
    Assert.AreEqual(target, valid); // PASSES
    Assert.AreEqual(valid, target); // FAILS
    

    我假设这是因为在第一个断言中,它调用field.Equals(),在第二个断言中,它调用String.Equals()。显然,我从错误的角度来看待这个问题。有人能给我一些见解吗?

    6 回复  |  直到 15 年前
        1
  •  9
  •   Jon Skeet    15 年前

    string object.Equals .

    我个人会尝试重新设计它,这样您就不会将验证作为类型本身的一部分—使其成为业务实体(或其他实体)的相关属性的一部分。

        2
  •  5
  •   Eugene Yokota    15 年前

    这将在中详细描述 Effective Java 作为第8项:在超控时遵守总合同 equals

    等于 方法实现一个等价关系。

    x.equals(null) false . 引用的打破对称的例子与你的相似。

    field 班级意识到 string 类不知道 领域

        3
  •  4
  •   Chris Thornhill    15 年前

    string valid = "Some String";
    field target = new field(valid);
    Assert.AreEqual(target.toString(), valid); 
    Assert.AreEqual(valid, target.toString());
    
        4
  •  0
  •   Scott Whitlock    15 年前

    根据每个人的反馈和我自己的需求,以下是我提出的可能解决方案(我正在修改Equals方法,如下所示):

    public override bool Equals(Object obj)
    {
        if (obj == null)
        {
            return false;
        }
    
        field f = obj as field;
        if (f != null)
        {
            return this == f;
        }
        else
        {
            return obj.Equals(this);
        }
    }
    

    而且,现在这两项都失败了:

    string valid = "Some String";
    field target = new field(valid);
    Assert.AreEqual(target, valid); // FAILS
    Assert.AreEqual(valid, target); // FAILS
    

    这两项都通过了:

    string valid = "Some String";
    field target = new field(valid);
    Assert.AreEqual(target.ToString(), valid); // PASSES
    Assert.AreEqual(valid, target.ToString()); // PASSES
    

    这两项都通过了:

    field f1 = new field("Some String");
    field f2 = new field("Some String");
    Assert.AreEqual(f1, f2); // PASSES
    Assert.AreEqual(f2, f1); // PASSES
    
        5
  •  0
  •   Gishu    15 年前

    这是字符串#等于

    public override bool Equals(object obj)
    {
        string strB = obj as string;
        if ((strB == null) && (this != null))
        {
            return false;
        }
        return EqualsHelper(this, strB);
    }
    

    为String#Equals提供字符串以外的参数将返回false。我建议“重新思考”来解决这个问题。

        6
  •  0
  •   druid    11 年前

    object.ReferenceEquals()

    public static bool operator ==(field x, Object y)
    {
        if (object.ReferenceEquals(x, null) && object.ReferenceEquals(y, null))
        {
            return true;
        }
        else if (object.ReferenceEquals(x, null) || object.ReferenceEquals(y, null))
        {
            return false;
        }
        else
        {
            return (x.m_field == y.ToString());
        }
    }