比较两个对象

3

我有以下实体

public class Employee
{
    public int EmpId { get; set; }
 }

我该如何比较两个对象?谢谢。


所以你想要的结果是一个新列表,其中包含lst1和lst2中都存在的所有元素,并且相等意味着所有属性都必须相互相等? - Øyvind Bråthen
2
超级重复的比较两个集合是否相等以及更多的问题(请查看相关问题)。 - Alastair Pitts
@Alastair - 对我来说似乎不一样。那个问题检查两个基本对象集合是否相等。而这个问题是针对两个不同列表中的单个复杂项进行比较。 - Øyvind Bråthen
4个回答

5

在您的类型(在此示例中为Employee)上实现IEquatable<T>,然后使用Enumerable.SequenceEqual

bool equal = Enumerable.SequenceEqual(lst1, lst2);

如果您无法修改Employee类,您也可以为Employee创建自定义的IEqualityComparer<T>,并使用Enumerable.SequenceEqual的其他重载。

bool equal = lst1.SequenceEqual(lst2, new EmployeeComparer());

请注意,只有当两个集合包含相同顺序的相等对象时,它们才被视为相等。
如果项目的顺序不重要,我会使用类似这样的方法:
bool equal = lst1.Count == lst2.Count && lst1.Count == lst1.Intersect(lst2).Count();

您还可以使用 IntersectIEqualityComparer<T> 一起使用。
更新:
看起来您想比较任何对象,即使它们没有实现 IEquatable<T>。下面是一个等式比较器的示例,如果可用,则使用 IEquatable<T>,如果类型是集合,则使用 Enumerable.SequenceEqual,否则使用反射递归检查类型的公共属性:
class ReflectionComparer<T> : IEqualityComparer<T>
{
    public bool Equals(T x, T y)
    {
        Type type = typeof(T);
        if( typeof(IEquatable<T>).IsAssignableFrom(type) )
            return EqualityComparer<T>.Default.Equals(x, y);

        Type enumerableType = type.GetInterface(typeof(IEnumerable<>).FullName);
        if( enumerableType != null )
        {
            Type elementType = enumerableType.GetGenericArguments()[0];
            Type elementComparerType = typeof(ReflectionComparer<>).MakeGenericType(elementType);
            object elementComparer = Activator.CreateInstance(elementComparerType);
            return (bool)typeof(Enumerable).GetMethod("SequenceEqual")
                                           .MakeGenericMethod(elementType)
                                           .Invoke(null, new object[] { x, y, elementComparer });
        }

        foreach( PropertyInfo prop in type.GetProperties() )
        {
            Type propComparerType = typeof(ReflectionComparer<>).MakeGenericType(prop.PropertyType);
            object propComparer = Activator.CreateInstance(propComparerType);
            if( !((bool)typeof(IEqualityComparer<>).MakeGenericType(prop.PropertyType)
                                                   .GetMethod("Equals")
                                                   .Invoke(propComparer, new object[] { prop.GetValue(x, null), prop.GetValue(y, null) })) )
                return false;
        }
        return true;
    }

    public int GetHashCode(T obj)
    {
        throw new NotSupportedException();
    }
}

我没有实现GetHashCode,因为Enumerable.SequenceEqual不需要它。

这应该能够做到你想要的(但要注意,这并不是非常高效的;不要在性能关键代码中使用它)。


@mcUser1:我添加了一个通用的IEqualityComparer<T>实现,如果没有更好的方法存在,它将使用反射来比较对象。希望这能帮到你。 - Sven

1

您需要为您的对象实现IEqualityComparer,然后在Union方法中使用它。


0
在你的Employee类中重写Equals()和GetHashCode()方法。
public class Employee
{
    public int EmpId { get; set; }
    public string EmpName { get; set; }
    public int EmpAge { get; set; }
    public string EmpSex { get; set; }

    public override bool Equals(object obj)
    {
        Employee other = obj as Employee;
        return null != other
               && other.EmpId == this.EmpId
               && other.EmpName == this.EmpName
               && other.EmpAge == this.EmpAge
               && other.EmpSex == this.EmpSex;
    }

    public override int GetHashCode()
    {
        return (EmpId + "_" + EmpName + "_" + EmpAge + "_" + EmpSex).GetHashCode();
    }
}


bool AreEqual<T>(IEnumerable<T> ls1, IEnumerable<T> ls2)
{
    return ls1.Count() == ls2.Count() && !ls1.Any(e => !ls2.Contains(e)) && !ls2.Any(e => !ls1.Contains(e));
}

    void Test()
    {
        Employee e1 = new Employee() { EmpAge = 20, EmpId = 123, EmpName = "XYZ", EmpSex = "M" };
        Employee e2 = new Employee() { EmpAge = 20, EmpId = 1232, EmpName = "XYZ", EmpSex = "M" };
        Employee e3 = new Employee() { EmpAge = 20, EmpId = 1232, EmpName = "XYA", EmpSex = "M" };
        Employee e4 = new Employee() { EmpAge = 20, EmpId = 1232, EmpName = "XYF", EmpSex = "M" };

        List<Employee> ls1 = new List<Employee>{e4, e3, e1, e2};
        List<Employee> ls2 = new List<Employee>{e1, e2, e3, e4};

        bool result = AreEqual(ls1, ls2); // true

        ls1 = new List<Employee>{e4, e3, e1, e3};
        ls2 = new List<Employee>{e1, e2, e3, e4};

        result = AreEqual(ls1, ls2); // false
    }

0

如果您想比较任何类型的两个实例,您可能会考虑使用反射,但我确定这不是正确的方法,我们只是利用了框架。

作为一种破解的解决方案,您可以查看下面的代码。

 static void Main(string[] args)
    {
        Employee e1 = new Employee() { EmpAge = 20, EmpId = 123, EmpName = "XYZ", EmpSex = "M" };
        Employee e2 = new Employee() { EmpAge = 20, EmpId = 123 , EmpName = "XYq", EmpSex = "M" };

        Person p1 = new Person() { Age = 20, name ="ABC"  };
        Person p2 = new Person() { Age = 20, name = "ABC" };

        Console.WriteLine("Employee Equality :" + IsObjectEquals(e1, e2).ToString());
        Console.WriteLine("Person Equality :" +IsObjectEquals(p1, p2).ToString());
        Console.ReadLine();
    }


    public static bool IsObjectEquals(object obj1, object obj2)
    {

       PropertyInfo[] props1 = obj1.GetType().GetProperties();
       PropertyInfo[] props2 = obj2.GetType().GetProperties();



       foreach (PropertyInfo pinfo in props1)
       {
           var val1 = pinfo.GetValue(obj1, null);
           var val2 = pinfo.GetValue(obj2, null);

           if (val1.ToString().Trim() != val2.ToString().Trim())
           {
                    return false;
           }


       }

       return true;

    }

你可以将第一个集合中的obj1和第二个集合中的obj2发送。 - TalentTuner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接