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?
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();
See more on this question at Stackoverflow