简体   繁体   中英

Linq Except returning entire first set with custom comparer

I have two List<MyObject> , with MyObject like so

public class MyObject
{
  public string Item {get; set;};
  public string Country {get; set;};
  public int Phone {get; set;};
}

I wish to find objects that are in List A but not in List B, however the objects do not share reference so I want to compare by all the properties on the object. I have this which overrides IEqualityComparer

    public class MyObjectComparer : IEqualityComparer<MyObject>
    {
        private PropertyInfo[] publicInstanceProperties;

        public MyObjectComparer()
        {
            publicInstanceProperties = typeof(MyObject).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        }

        public bool Equals(MyObject x, MyObject y)
        {
            foreach (PropertyInfo property in publicInstanceProperties)
            {
                if (property.CanRead && property.GetIndexParameters().Length == 0 && !property.GetValue(x).Equals(property.GetValue(y)))
                {
                    return false;
                }
            }
            return true;
        }

        public int GetHashCode(MyObject obj)
        {
            long hashCodes = 0;
            foreach (PropertyInfo property in typeof(MyObject).GetProperties())
            {
                var value = property.GetValue(obj) ?? 0;
                hashCodes += value.GetHashCode();
            }

            return (int)(hashCodes % int.MaxValue);
        }
    }

And I call it like this:

var comparer = new MyObjectComparer();
var result = listA.Except(listB, comparer);

However when I do this the result is always just the entire contents of list A , even if the properties of an object in list A and list B are identical. For instance, if I have

var listA = new List<MyObject>
{
  new MyObject
  {
    Item = "ItemName",
    Country = "Spain",
    Phone = 123456789
  },
  new MyObject
  {
    Item = "DifferentName",
    Country = "Portugal",
    Phone = 00000
  }
};

var listB = new List<MyObject>
{
  new MyObject
  {
    Item = "ItemName",
    Country = "Spain",
    Phone = 123456789
  }
};

Then my code returns the entire set of listA , even though it should only return the second item in listA . Please let me know if I am failing to understand how this works. Thank you.

Demo on dotnet fiddle

I've run your code and it gives us the result as expected.

var comparer = new MyObjectComparer();
var result = listA.Except(listB, comparer).ToList();

Console.WriteLine("Count: " + result.Count);     
Console.WriteLine(JsonConvert.SerializeObject(result[0]));

Output

Count: 1
{"Item":"DifferentName","Country":"Portugal","Phone":0}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM