Object.Equals()方法在看似相等的对象上返回false。

4
我正在编写一个C#应用程序,其中我使用类型为Airport的对象列表来填充DataGridView。我目前正在编写按下按钮后删除一个对象的方法。
参考代码中,dgvF是包含Flights List<Flights>DataGridView,我还有一个dgvA用于我的Airports List<Airports>
private void bajaAeropuerto_Click(object sender, EventArgs e)
{
    String c = city.Text;
    String id = idAirport.Text;

    Airport delete = new Airport(c, id);

    //Select all Flights which reference the "delete" airport
    foreach (DataGridViewRow row in listaVuelos.Rows)
    {
        Flight v = (Flight)row.DataBoundItem;
        Airport aO = v.fromCity;
        Airport aD = v.toCity;

        if(delete.Equals(aO) || delete.Equals(aD))
        {
            dgvF.MultiSelect = true;
            row.Selected = true;
        }
    }

    if (airports.Contains(delete))
    {
        airports.Remove(delete);
    }
    else
    {
        //show message airport doesn't exist
    }

    dgvAirports.Update();
    dgvAirports.Refresh();
}

然而,if(delete.Equals(aO) || delete.Equals(aD))if (airports.Contains(delete)) 这两行代码从未返回true。我在调试模式下运行应用程序,尽管有一刻delete 的值是 {"TIJ- Tijuana"}aD 的值是 {"TIJ - Tijuana"},但布尔运算仍然返回false。我不知道为什么,这是因为我的.toString()方法重写了吗?因为我需要它在我的飞行操作的DataGridView中显示完整的机场名称。
我的AirportFlight类定义如下:
class Airport
{
    public String city{ get; set; }
    public String id { get; set; }

    public Airport(String ciudad, String id)
    {
        this.city = city;
        this.id = id;
    }

    public override string ToString()
    {
        return id + "- " + city; //Ej. MX- Mexico City
    }
}

并且

class Flight
{
    public String id { get; set; }
    public Airport fromCity{ get; set; }
    public Airport toCity { get; set; }
    public int price{ get; set; }

    public Flight(String id, Aeropuerto origen, Aeropuerto destino, int precio)
    {
        this.id = id;
        this.fromCity = origen;
        this.toCity = destino;
        this.price= precio;
    }
}
3个回答

7
您在尝试删除一个新实例之前创建了它。使用object.Equals进行匹配将通过引用进行。这意味着新实例的"内存地址指针"将与现有实例的"内存地址指针"进行比较。这永远不可能是真的。
您应该在类中重写并实现EqualsGetHashCode,以影响比较。
public override bool Equals(object o)
{
    return o is Airport && ((Airport)o).id == this.id;
}

public override int GetHashCode()
{
    return this.id.GetHashCode();
}

我认为问题可能是我通过对象引用而不是属性值调用了equal,但我在msdn上读到,即使对于具有不同引用但相同属性值的两个对象,.Equals()也会返回true。https://msdn.microsoft.com/es-es/library/bsc2ak47%28v=vs.110%29.aspx 这是不是不正确的?还是我做错了什么? - Ces
默认实现使用 ReferenceEquals... 您应该实现自己的 Equals - Patrick Hofman
抱歉,我认为我可能误解了 MSDN 的示例或其他内容,但我按照您建议的实现了重写方法,它起作用了。谢谢! - Ces
没问题。静态 object.Equals 调用第一个成员的 Equals,因此如果该方法被重写,它会调用那个重写的方法。 - Patrick Hofman
1
@Ces Equals仅适用于struct - 如果您将Airport类更改为struct,则a == b将执行值比较,而在类上,则默认执行引用比较。 您可以重写相等运算符以及EqualsGetHashCode方法(如果需要更改其中一个,则应始终重写所有这些方法)。 - Luaan

1
你需要重写EqualsGetHashCode,正如Patrick所说,这是我会这样做的方式:
请参考https://msdn.microsoft.com/en-us/library/vstudio/336aedhh%28v=vs.100%29.aspx获取更多信息。
class Airport
{
    ...

    public override bool equals(Object obj)
    {
        //types must be the exactly the same for non-sealed classes
        if (obj == null || obj.GetType() != GetType()) 
          return false;
        return equals((AirPort)obj);
    }

    private bool equals(AirPort other)
    {
        if (other == null)
          return false;
        return other.id == id; //only id should be needed if unique
    }

    public override int GetHashCode()
    {
        return id.GetHashCode(); //again, only id needed
    }
}

或者如果sealed
sealed class Airport
{
    ...

    public override bool equals(Object obj)
    {
        return equals(obj as AirPort);
    }

    public bool equals(AirPort other)
    {
        if (other == null)
          return false;
        return other.id == id; //only id should be needed if unique
    }

    public override int GetHashCode()
    {
        return id.GetHashCode(); //again, only id needed
    }
}

1
感谢提供的参考链接,对我将来可能很有用。 - Ces

0
如果当前实例是引用类型,则Equals(Object)方法测试引用相等性,调用Equals(Object)方法等同于调用ReferenceEquals方法。
  public override bool Equals(Object obj) {
  // Perform an equality check on two rectangles (Point object pairs). 
      if (obj == null || GetType() != obj.GetType()) 
         return false;
       Airport r = (Airport)obj;
      return fromCity.Equals(r.fromCity) && toCity .Equals(r.toCity );
  }

  public override int GetHashCode() {
     return Tuple.Create(fromCity, toCity ).GetHashCode();
  }

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