Except() Method with CustomPropertyEqualityComparer and NO Distinct

i use my own CustomPropertyEqualityComparer to compare List of objects dynamically by custom properties.

This is the CustomPropertyEqualityComparer:

public class CustomPropertyEqualityComparer<T> : IEqualityComparer<T> where T : class
{
    public PropertyInfo[] _PropertyInfos;

    /// <summary>
    /// Creates a new instance of PropertyComparer.
    /// </summary>
    /// <param name="propertyName">The name of the property on type T 
    /// to perform the comparison on.</param>
    public CustomPropertyEqualityComparer(params string[] propertyName)
    {
        _PropertyInfos = new PropertyInfo[propertyName.Length];

        //store a reference to the property info object for use during the comparison
        for (int i = 0; i < propertyName.Length; i++)
        {
            _PropertyInfos[i] = typeof(T).GetProperty(propertyName[i], BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);
            if (_PropertyInfos == null)
            {
                throw new ArgumentException(string.Format("{0} is not a property of type {1}.", propertyName, typeof(T)));
            }
        }
    }

    public bool Equals(T x, T y)
    {
        foreach (PropertyInfo propInf in _PropertyInfos)
        {
            if (propInf != null)
            {
                //get the current value of the comparison property of x and of y
                object xValue = propInf.GetValue(x, null);
                object yValue = propInf.GetValue(y, null);

                //if the xValue is null then we consider them equal if and only if yValue is null
                if (xValue != yValue && (xValue == null || !xValue.Equals(yValue)))
                {
                    return false;
                }    
            }               

        }
        return true;
    }

    public int GetHashCode(T obj)
    {
        int HashCode = 0;

        foreach (var p in _PropertyInfos)
        {
            if (p != null)
            {
                HashCode += p.GetHashCode();    
            }                
        }

        return HashCode;
    }
}

And i use it like this way:

List<T> ListNewObj = ListObj2.Except(ListObj1, CustomPropertyComparer).ToList();

Lets say ListObj2 has two identical items and ListObj1 is empty, ListNewObj would only contain one item from ListObj2, but i want them both in the ListNewObj,

The Problem is, that it seems that after a Except() and Intersect() a Distinct() follows automatically, but how can i avoid this?

Jon Skeet
people
quotationmark

The Problem is, that it seems that after a Except() and Intersect() a Distinct() follows automatically

Not really. It just means that it's a set-based operation - so the result will never contain two equal (under your equality comparison) results. If you look at my sample implementation you'll see that it doesn't have to be a two step operation. It's unfortunate that it's not very clearly documented though.

The simplest way to avoid this is just to perform the filtering yourself:

var excludedSet = new HashSet<T>(ListObj1, CustomPropertyComparer);
var result = ListObj2.Where(x => !excludedSet.Contains(x))
                     .ToList();

people

See more on this question at Stackoverflow