在下面的代码块中,我希望dictCars包含: {雪佛兰:卡马罗,道奇:充电器}
但是,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实施有什么问题?
提前致谢!
答案 0 :(得分:7)
你需要告诉包含使两个Car
相等的内容。默认情况下,它将使用ReferenceEquals
,如果它们是同一个实例,它们只会调用两个等于的对象。
覆盖Equals
课程中的GetHashCode
和Car
,或定义IEqualityComparer<Car>
课程并将其传递给Contains
。
如果两个具有相同Car
的{{1}}“相等”,那么实现非常简单:
CarID
答案 1 :(得分:5)
您的Car
班级是参考类型。默认情况下,引用类型通过引用相互比较,这意味着如果它们在内存中引用相同的实例,则它们被认为是相同的。在您的情况下,如果它们包含相同的值,则希望它们被视为相等。
要更改平等行为,您需要覆盖Equals
和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
的有用实现。
答案 2 :(得分:2)
您假设具有相同CarID和CarName的两个Car实例相等。
这是不正确的。默认情况下,每个new Car(...)
与其他汽车的不同,因为它们是对不同对象的引用。
有几种方法可以“修复”:
为您的汽车使用struct
而不是class
。
Structs继承ValueType
的默认实现Equals
,它会比较所有字段和属性以确定相等。
请注意,在这种情况下,建议您将Car
结构不可变为avoid common problems with mutable structs。
<强> Override Equals and GetHashCode 强>
这样,List.Contains
就会知道您打算使用相同ID和名称的汽车。
使用其他方法代替List.Contains
。
例如,Enumerable.Any
允许您指定可匹配的谓词:
bool exists = myCars.Any(car => car.ID == Convert.ToInt64(strCar.Split(':')[1])
&& car.Name = strCar.Split(':')[2]);
答案 3 :(得分: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
答案 4 :(得分: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;
}
答案 5 :(得分:0)
您的汽车类需要实现IEquatable接口并定义Equals方法,否则contains方法正在比较基础引用。
答案 6 :(得分:0)
集合永远不会“包含”使用默认new
比较的新Object.Equals
ed对象。 (默认比较为ReferenceEquals
,只是比较实例。将现有Car
与new Car()
进行比较
要以这种方式使用Contains
,您需要:
覆盖Car.Equals
(和Car.GetHashCode
)以指定相同的含义,或
实施IEqualityComparer<Car>
比较实例,并在调用Contains
时指定。
请注意第一个选项中的副作用,Car.Equals(Car)
的其他用法也会使用此比较。
否则,您可以使用Any
并自行指定比较(但恕我直言,这有点气味 - 汽车应该知道如何比较自己):
if(myCars.Any(c=> c.CarID == Convert.ToInt64(strCar.Split(':')[1]) && c.CarName == strCar.Split(':')[2]))
答案 7 :(得分: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);
答案 8 :(得分:-1)
myCars.Contains(newCar)
myCars.Where(c => c.CarID == newCar.CarID && c.CarName==newCar.CarName).Count() > 0