Except() - 带有 CustomPropertyEqualityComparer 和 NO Distinct 的方法
Except()-Method with CustomPropertyEqualityComparer and NO Distinct
我使用自己的 CustomPropertyEqualityComparer 通过自定义属性动态比较对象列表。
这是 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;
}
}
我是这样使用的:
List<T> ListNewObj = ListObj2.Except(ListObj1, CustomPropertyComparer).ToList();
假设 ListObj2 有两个相同的项目,ListObj1 是空的,ListNewObj 将只包含 ListObj2 中的一个项目,但我希望它们都在 ListNewObj 中,
问题是,似乎在 Except() 和 Intersect() 之后自动跟随一个 Distinct(),但我如何避免这种情况?
The Problem is, that it seems that after a Except() and Intersect() a Distinct() follows automatically
不是真的。这只是意味着它是一个基于集合的操作——所以结果永远不会包含两个相等的(在你的平等比较下)结果。如果您查看我的 sample implementation,您会发现它不一定是两步操作。不幸的是,它没有被非常清楚地记录下来。
避免这种情况的最简单方法就是自己执行过滤:
var excludedSet = new HashSet<T>(ListObj1, CustomPropertyComparer);
var result = ListObj2.Where(x => !excludedSet.Contains(x))
.ToList();
我使用自己的 CustomPropertyEqualityComparer 通过自定义属性动态比较对象列表。
这是 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;
}
}
我是这样使用的:
List<T> ListNewObj = ListObj2.Except(ListObj1, CustomPropertyComparer).ToList();
假设 ListObj2 有两个相同的项目,ListObj1 是空的,ListNewObj 将只包含 ListObj2 中的一个项目,但我希望它们都在 ListNewObj 中,
问题是,似乎在 Except() 和 Intersect() 之后自动跟随一个 Distinct(),但我如何避免这种情况?
The Problem is, that it seems that after a Except() and Intersect() a Distinct() follows automatically
不是真的。这只是意味着它是一个基于集合的操作——所以结果永远不会包含两个相等的(在你的平等比较下)结果。如果您查看我的 sample implementation,您会发现它不一定是两步操作。不幸的是,它没有被非常清楚地记录下来。
避免这种情况的最简单方法就是自己执行过滤:
var excludedSet = new HashSet<T>(ListObj1, CustomPropertyComparer);
var result = ListObj2.Where(x => !excludedSet.Contains(x))
.ToList();