简体   繁体   中英

Object.Equals() method returns false on seemingly equal object

I'm writing a C# application where I populate a DataGridView with a list of objects of type Airport . I'm currently writing the method to delete one after pressing a button.

For reference dgvF is a DataGridView containing the flights List<Flights> , I also have a dgvA for my 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();
}

However, the if(delete.Equals(aO) || delete.Equals(aD)) and if (airports.Contains(delete)) lines never return true, I run the Application on debug mode and although at one point delete is {"TIJ- Tijuana"} and aD is {"TIJ - Tijuana"} the boolean operation still returns false . I don't really know why. Is it because of my .toString() overrided method? Because I need it to display the full Airport name on my DataGridView of Flight methods.

My Airport and Flight classes are defined as follows:

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

and

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

You are creating a new instance before trying to delete it. Matching using object.Equals will be done by reference. That means that the 'address pointer in memory' is checked against the 'address pointer in memory' of the new one. That can never be true.

You should override and implement Equals and GetHashCode in your class in order to influence the comparison.

public override bool Equals(object o)
{
    return o is Airport && ((Airport)o).id == this.id;
}

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

You need to override Equals and GetHashCode as Patrick has said, this is how I would do it:

Refer to https://msdn.microsoft.com/en-us/library/vstudio/336aedhh%28v=vs.100%29.aspx for more info.

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

Or if 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
    }
}

If the current instance is a reference type, the Equals(Object) method tests for reference equality, and a call to the Equals(Object) method is equivalent to a call to the ReferenceEquals method

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM