通用IEqualityComparer使用反射和属性来标记我想要比较的内容

本文关键字:我想要 比较 IEqualityComparer 反射 属性 通用 | 更新日期: 2023-09-27 18:33:22

交叉点应该产生 0 条记录,因为名字和姓氏不合时宜。 我哪里做错了....?我怀疑是在平等实施中。

谢谢你,所有的问题都解决了(特别感谢Lasse V. Karlsen在钱上用gethashcode):等于加上哈希码错误解决了问题。

测试代码

    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; }
    }

通用IEqualityComparer使用反射和属性来标记我想要比较的内容

根据我的高中数学:

SetA = {test1, test2}
SetB = {test1, test2}
SetA = SetB (conceptually speaking) => SetA (intersect) SetB = SetA

或者你期望看到什么?

如果将其更改为

SetA = {test1}
SetB = {test2}

你会得到{0}(空集)。

无论如何,我不建议将其用于生产代码。至少,当您已经在反射助手中检查了类时,缓存属性信息。

如果您有很多比较,则此代码将运行(相对)非常慢(正如您在实现此代码的推理中所暗示的那样)。虽然我非常喜欢避免编写样板代码,但有时由于性能/可维护性原因,编写它是值得的。