Trying to implement a method that can compare any two lists but it always returns false

て烟熏妆下的殇ゞ 提交于 2020-01-03 19:35:11

问题


I'm trying to make a method that can compare any two lists for equality. I'm trying to compare them in a way that validates that every element of one list has the same value as every element of another list. My Equals method below always returns false, can anyone see why that is?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public class IEnumerableComparer<T> : IEqualityComparer<IEnumerable<T>>
{
    public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
    {
        for(int i = 0; i<x.Count();i++){
          if(!Object.Equals(x.ElementAt(i), y.ElementAt(i))){
             return false;
          }
        }
        return true;
    }

    public int GetHashCode(IEnumerable<T> obj)
    {
        if (obj == null)
            return 0;

        return unchecked(obj
            .Select(e => e.GetHashCode())
            .Aggregate(0, (a, b) => a + b)); 
    }
}

Here is my data I'm using to test this Equals method:

 static void Main(string[] args)
        {
            Car car1 = new Car();
            car1.make = "Toyota";
            car1.model = "xB";

            Car car2 = new Car();
            car2.make = "Toyota";
            car2.model = "xB";

            List<Car> l1 = new List<Car>();
            List<Car> l2 = new List<Car>();
            l1.Add(car1);
            l2.Add(car2);

           IEnumerableComparer<Car> seq = new IEnumerableComparer<Car>();

           bool b = seq.Equals(l1, l2);

           Console.Write(b); //always says false
           Console.Read();
        }
    }

Car class:

   class Car
    {
        public String make { get; set; }
        public String model { get; set; }
    }

回答1:


The default version of Equals compares references (for reference types). There are three possible solutions to your problem:

  • override Equals and GetHashCode for the Car class

  • add another version of IEnumerableComparer<T> constructor accepting IEqualityComparer<T> which will be used to compare individual instances and provide its implementation for each use case

  • use only value types, as for them the default version of Equals will behave as you expect. Note that all fields and properties of these value types will have to conform to the 1st or 3rd option given here (i.e. either have Equals and GetHashCode overridden or be a value type also). It's not really a recommended solution in general, I just mention it as a theoretical possibility. In your case it would help though - try changing class Car to struct Car.

Also, as correctly pointed out by wageoghe's answer you can use the SequenceEqual method instead of writing your own implementation, but still you need to comply to one of the solutions given above (using this SequenceEqual overload for the second option).




回答2:


Maybe I'm missing something, but why not use SequenceEqual?

http://msdn.microsoft.com/en-us/library/bb348567(v=vs.110).aspx

Bool b = l1.SequenceEqual(l2);

Note that the objects in the sequences still must implement Equals and GetHashCode correctly.




回答3:


Give your car the overrides as well:

class Car
{
    public String make { get; set; }
    public String model { get; set; }
    public override bool Equals(object obj)
    {
        var other = obj as Car;
        return (other != null) 
                && (this.make == other.make) 
                && (this.model == other.model); 
    }
    public override int GetHashCode()
    {
        return make.GetHashCode() ^ model.GetHashCode();
    }
}


来源:https://stackoverflow.com/questions/19883357/trying-to-implement-a-method-that-can-compare-any-two-lists-but-it-always-return

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!