簡體   English   中英

c#列表<T> .Contains() 方法返回 False

[英]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類中覆蓋EqualsGetHashCode或定義一個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類是一種引用類型。 默認情況下,引用類型通過引用相互比較,這意味着它們被認為是相同的,如果它們引用相同的實例在內存中。 在您的情況下,如果它們包含相同的值,您希望它們被視為相等。

要更改相等行為,您需要覆蓋EqualsGetHashCode

如果僅當IDName相等時兩輛車才相等,則以下是相等成員的一種可能實現:

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結構不可變以避免可變結構的常見問題

  • 覆蓋 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]);

您可以通過實現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 ,它只是比較實例。將現有的Carnew Car()進行比較永遠不會是真的)

要以這種方式使用Contains ,您需要:

  1. 覆蓋Car.Equals (和Car.GetHashCode )以指定等效的含義,或

  2. 實現一個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM