[英]c# List<T>.Contains() Method Returns False
在下面的代碼塊中,我希望 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 實現有什么問題?
提前致謝!
您需要告訴 Contains 是什么使兩個Car
相等。 默認情況下,它將使用ReferenceEquals
,如果它們是相同的實例,它只會調用相等的兩個對象。
在Car
類中覆蓋Equals
和GetHashCode
或定義一個IEqualityComparer<Car>
類並將其傳遞給Contains
。
如果具有相同CarID
兩個Car
是“相等的”,那么實現就非常簡單:
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();
}
您的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
實現。
您假設具有相同 CarID 和 CarName 的兩個 Car 實例是相等的。
這是不正確的。 默認情況下,每輛new Car(...)
都與其他汽車不同,因為它們是對不同對象的引用。
有幾種方法可以“修復”:
為您的汽車使用struct
而不是class
。
結構繼承ValueType
的默認實現Equals
,它比較所有字段和屬性以確定相等性。
請注意,在這種情況下,建議您使Car
結構不可變以避免可變結構的常見問題。
這樣, 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]);
您可以通過實現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
您需要實現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;
}
您的汽車類需要實現接口 IEquatable 並定義一個 Equals 方法,否則 contains 方法正在比較底層引用。
集合永遠不能“包含”使用默認Object.Equals
比較的new
ed 對象。 (默認比較是ReferenceEquals
,它只是比較實例。將現有的Car
與new Car()
進行比較永遠不會是真的)
要以這種方式使用Contains
,您需要:
覆蓋Car.Equals
(和Car.GetHashCode
)以指定等效的含義,或
實現一個IEqualityComparer<Car>
來比較實例並在對Contains
的調用中指定。
請注意在第一個選項中的Car.Equals(Car)
, Car.Equals(Car)
其他用途也將使用此比較。
否則,您可以使用Any
並自己指定比較(但恕我直言,這聞起來有點有趣 - 汽車應該知道如何比較自己):
if(myCars.Any(c=> c.CarID == Convert.ToInt64(strCar.Split(':')[1]) && c.CarName == strCar.Split(':')[2]))
您需要實現 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);
myCars.Contains(newCar)
myCars.Where(c => c.CarID == newCar.CarID && c.CarName==newCar.CarName).Count() > 0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.