通用 IEqualityComparer 使用反射和属性来标记我想要比较的内容
Posted
技术标签:
【中文标题】通用 IEqualityComparer 使用反射和属性来标记我想要比较的内容【英文标题】:generic IEqualityComparer using reflection and attributes to mark what i want to compare 【发布时间】:2015-02-03 08:34:52 【问题描述】:Intersect 应该产生 0 条记录,因为 firstname 和 lastname 不匹配。 我哪里做错了....?我怀疑是在 equals 实现中。
谢谢你所有的问题都解决了(特别感谢 Lasse V. Karlsen 用 gethashcode 赚钱):Equals 加上哈希码错误解决了这个问题。
测试代码
var test1 = new ClassA employeeid = 1, firstName = "a", lastname = "a" ;
var test2 = new ClassA employeeid = 1, firstName = "a", lastname = "b" ;
IList<ClassA> listA = new List<ClassA>();
listA.Add(test1);
IList<ClassA> listB = new List<ClassA>();
listB.Add(test2);
//Actual Code
var Reflection = new ReflectionHelper();
var ListClassA = Reflection.GetPropertyNames<ClassA>();
var results = listA.Intersect(listB, new Compare<ClassA>(ListClassA)).ToList();
我的比较器
public class KeyComparerAttribute : Attribute
public class Compare<T> : IEqualityComparer<T> where T : class
IList<string> keyProperties = new List<string>();
public Compare(IList<string> keyProperties)
this.keyProperties = keyProperties;
public bool Equals(T x, T y)
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
var reflection = new ReflectionHelper();
foreach (var propName in keyProperties)
string val1 = reflection.GetPropertyValue<T>(propName, x);
string val2 = reflection.GetPropertyValue<T>(propName, y);
if (!val1.Equals(val2))
return false;
//if never false then it must be true....
return true;
public int GetHashCode(T obj)
int hash = 17;
foreach (var propInfo in keyProperties)
var myValue = reflection.GetPropertyValue(propName:propInfo, src: obj);
hash = hash * 23 + myValue.GetHashCode();
return hash;
我的助手类仅供参考
public class ReflectionHelper
public IList<string> GetPropertyNames<T>()
IList<string> propertyNames = new List<string>();
var propertyInfos = typeof(T).GetProperties(
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Default |
BindingFlags.Instance).ToList().
Where(prop => Attribute.IsDefined(prop, typeof(KeyComparerAttribute)));
// write property names
if (propertyInfos.ToList().Count > 0)
foreach (PropertyInfo propertyInfo in propertyInfos)
propertyNames.Add(propertyInfo.Name);
return propertyNames;
public string GetPropertyValue<T>(string propName, T src)
return src.GetType().GetProperty(propName).GetValue(src, null).ToString();
A 类
public class ClassA
public int employeeid get; set;
[KeyComparer]
public string firstName get; set;
[KeyComparer]
public string lastname get; set;
【问题讨论】:
无论如何,即使比较器确实有效,他也会将相同的两个实例放在两个列表中,我不明白他在这里测试什么。 此外,他为他的场景实现了一个非常不正确的 GetHashCode,它应该使用与比较器相同的属性来计算哈希码。 它们实际上应该是相同的哈希码属性。 我是说你的实现是错误的。您阅读了 propertyinfo 对象,它们总是相同的。它应该基于这些属性的值。 请不要更新您的问题以包含答案。如果您回答了自己的问题,请将您的解决方案作为答案发布并接受。 ***.com/help/self-answer 【参考方案1】:根据我的高中数学:
SetA = test1, test2
SetB = test1, test2
SetA = SetB (conceptually speaking) => SetA (intersect) SetB = SetA
或者你期望看到什么?
如果你改成
SetA = test1
SetB = test2
你会得到0
(空集)。
无论如何,我不建议将此作为产品代码。至少,当您已经在 ReflectionHelper 中检查了一个类时,缓存属性信息。
如果您有很多比较(正如您在实现此代码的推理中所暗示的那样),此代码将运行(比较)非常缓慢。虽然我非常喜欢避免编写样板代码,但由于性能/可维护性的原因,有时值得编写它。
【讨论】:
这就是我得到结果 =2 的重点。我的目标是按照你的高中数学要求得到 0。 使用 except 而不是 intersect then ;-) var results = listA.Except(listB, new Compare以上是关于通用 IEqualityComparer 使用反射和属性来标记我想要比较的内容的主要内容,如果未能解决你的问题,请参考以下文章