0

在下面的代码块中,我希望 dictCars 包含: { Chevy:Camaro, Dodge:Charger }

但是,dictCars 空空如也。因为此行每次调用时都返回 false:

if(myCars.Contains(new Car(Convert.ToInt64(strCar.Split(':')[1]),strCar.Split(':')[2])))

代码块:

public class Car
{
    public long CarID { get; set; }

    public string CarName { get; set; }

    public Car(long CarID, string CarName)
    {
        this.CarID = CarID;
        this.CarName = CarName;
    }
}

List<Car> myCars = new List<Car>();
myCars.Add(new Car(0,"Pinto"));
myCars.Add(new Car(2,"Camaro"));
myCars.Add(new Car(3,"Charger"));

Dictionary<string, string> dictCars = new Dictionary<string, string>();
string strCars = "Ford:1:Mustang,Chevy:2:Camaro,Dodge:3:Charger";
String[] arrCars = strCars.Split(',');
foreach (string strCar in arrCars)
{
    if(myCars.Contains(new Car(Convert.ToInt64(strCar.Split(':')[1]),strCar.Split(':')[2])))
    {
        if (!dictCars.ContainsKey(strCar.Split(':')[0]))
        {
            dictCars.Add(strCar.Split(':')[0], strCar.Split(':')[2]);
        }
    }
}

return dictCars;

问题:我的 List.Contains 实现有什么问题?

提前致谢!

4

9 回答 9

7

你需要告诉 Contains 是什么让两个Cars 相等。默认情况下,它将使用ReferenceEqualswhich 只会调用两个对象相等,如果它们是相同的实例

在您的类中覆盖Equalsand或定义一个类并将其传递给.GetHashCodeCarIEqualityComparer<Car>Contains

如果两个Car相同的 sCarID是“相等的”,那么实现非常简单:

public override bool Equals(object o)
{
   if(o.GetType() != typeof(Car))
     return false;

   return (this.CarID == ((Car)o).CarID);
}

public override int GetHashCode()
{
  return CarID.GetHashCode();
}
于 2012-10-11T15:44:16.803 回答
6

您的Car类是引用类型。默认情况下,引用类型通过引用相互比较,这意味着如果它们引用内存中的相同实例,则它们被认为是相同的。在您的情况下,如果它们包含相同的值,您希望它们被视为相等。

要更改相等行为,您需要覆盖Equalsand GetHashCode

如果两辆车仅在ID和相等时Name相等,则以下是相等成员的一种可能实现:

protected bool Equals(Car other)
{
    return CarID == other.CarID && string.Equals(CarName, other.CarName);
}

public override bool Equals(object obj)
{
    if (ReferenceEquals(null, obj))
        return false;
    if (ReferenceEquals(this, obj))
        return true;
    var other = obj as Car;
    return other != null && Equals(other);
}

public override int GetHashCode()
{
    unchecked
    {
        return (CarID.GetHashCode() * 397) ^ 
                (CarName != null ? CarName.GetHashCode() : 0);
    }
}

此实现由 ReSharper 自动创建。
它考虑了null的值和子类的可能性Car。此外,它提供了一个有用的实现GetHashCode

于 2012-10-11T15:43:17.747 回答
2

您假设具有相同 CarID 和 CarName 的两个 Car 实例是相等的。

这是不正确的。默认情况下,每辆汽车new Car(...)都与其他汽车不同,因为它们是对不同对象的引用。

有几种方法可以“修复”它:

  • 为您的汽车使用 astruct而不是 a 。class

    结构继承ValueType的默认实现Equals,它比较所有字段和属性以确定相等性。

    请注意,在这种情况下,建议您使Car结构不可变以避免可变结构的常见问题

  • 覆盖 Equals 和 GetHashCode

    这样,List.Contains将知道您希望具有相同 ID 和 Name 的 Cars 是相等的。

  • 使用另一种方法而不是List.Contains.

    例如,Enumerable.Any允许您指定可以匹配的谓词:

    bool exists = myCars.Any(car => car.ID == Convert.ToInt64(strCar.Split(':')[1])
                                    && car.Name = strCar.Split(':')[2]);
    
于 2012-10-11T15:45:07.300 回答
2

您可以通过实现添加此代码IEquatable

public class Car: IEquatable<Car>
{

    ......

    public bool Equals( Car other )
    {
        return this.CarID  == other.CarID && this.CarName == other.CarName;
    }
}

链接:http: //msdn.microsoft.com/fr-fr/library/vstudio/ms131187.aspx

于 2012-10-11T15:46:20.437 回答
1

您需要实施Equals。最有可能是:

public override bool Equals(object obj)
{
     Car car = obj as Car;
     if(car == null) return false;
     return car.CarID == this.CarID && car.CarName == this.CarName;
}
于 2012-10-11T15:46:47.890 回答
0

您的汽车类需要实现接口 IEquatable 并定义 Equals 方法,否则 contains 方法正在比较底层引用。

于 2012-10-11T15:43:31.887 回答
0

集合永远不能“包含”使用默认比较的新new编辑对象。Object.Equals(默认比较是ReferenceEquals,它只是比较实例。将现有的Car与 a进行比较永远不会是真的new Car()

Contains以这种方式使用,您需要:

  1. 覆盖Car.Equals(and Car.GetHashCode) 以指定等效的含义,或

  2. 实现一个IEqualityComparer<Car>来比较实例并在你的调用中指定它Contains

Car.Equals(Car)请注意,在第一个选项中,其他使用 of也将使用此比较的副作用。


否则,您可以Any自己使用并指定比较(但恕我直言,这闻起来有点滑稽——汽车应该知道如何比较自己):

if(myCars.Any(c=> c.CarID == Convert.ToInt64(strCar.Split(':')[1]) && c.CarName == strCar.Split(':')[2]))
于 2012-10-11T15:44:00.007 回答
0

您需要实现 IEqualityComparer

可以在此处找到有关如何操作的更多信息; http://msdn.microsoft.com/en-us/library/bb339118.aspx

// Custom comparer for the class 
 class CarComparer : IEqualityComparer<Car>
{
// Products are equal if their names and product numbers are equal. 
public bool Equals(Car x, Car y)
{

    //Check whether the compared objects reference the same data. 
    if (Object.ReferenceEquals(x, y)) return true;

    //Check whether any of the compared objects is null. 
    if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
        return false;

    //Check whether the properties are equal. 
    return x.CarID == y.CarID && x.CarName == y.CarName;
}

// If Equals() returns true for a pair of objects  
// then GetHashCode() must return the same value for these objects. 

public int GetHashCode(Car car)
{
    //Check whether the object is null 
    if (Object.ReferenceEquals(car, null)) return 0;

    //Get hash code for the Name field if it is not null. 
    string hashCarName = car.CarName == null ? 0 : car.CarName.GetHashCode();

    //Get hash code for the ID field. 
    int hashCarID = car.CarID.GetHashCode();

    //Calculate the hash code for the product. 
    return hashCarName ^ hashCarID;
}

检查是否相等;

CarComparer carComp = new CarComparer();
bool blnIsEqual = CarList1.Contains(CarList2, carComp);
于 2012-10-11T15:44:42.477 回答
-1
myCars.Contains(newCar)
myCars.Where(c =>  c.CarID == newCar.CarID && c.CarName==newCar.CarName).Count() > 0
于 2020-10-02T13:58:08.860 回答