在LINQ中比较两个类 - 得到'不匹配'

时间:2012-02-06 09:24:29

标签: c# linq

我有以下课程:

public class DocumentCompare
{
    public string Customer;
    public string Filename;
    public string Reference;
    public DateTime? Date;

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        DocumentCompare doc = obj as DocumentCompare;
        if ((Object)doc == null)
            return false;

        return (doc.Customer == Customer) && (doc.Date == Date) && (doc.Filename == Filename) && (doc.Reference == Reference);
    }

    public bool Equals(DocumentCompare doc)
    {
        if ((object)doc == null)
            return false;

        return (doc.Customer == Customer) && (doc.Date == Date) && (doc.Filename == Filename) && (doc.Reference == Reference);
    }

    public override int GetHashCode()
    {
        return string.Format("{0}_{1}_{2}_{3}",Customer,Filename,Reference,(Date == null ? "" : Date.Value.ToString())).GetHashCode();
    }
}

我将检索此类的2个列表 - 我想要做的是比较两者,并获得两者中不存在的列表。因此,如果项目存在于x列表中但不存在于y中,我想对此列表中的项目执行操作。如果项目存在于y列表中但不存在于x中,我想要执行不同的操作。

我该怎么做?使用LINQ我猜!

编辑:性能不是问题 - 这只会运行一次

3 个答案:

答案 0 :(得分:5)

听起来你只想要Except

foreach (var newItem in firstList.Except(secondList))
{
    ...
}

暂且不说:

  • 这不是生成哈希码的非常好的方法 - 在这里搜索其他问题。
  • Equals(object)委派给Equals(DocumentCompare)以避免重复逻辑
  • 可变类型不是平等比较的理想选择(特别是,你在字典中使用了一个值作为键,如果更改了相等敏感组件,则无法再次找到键)
  • 即使你希望它是可变的,封装的属性也比公共字段更好
  • 我要么密封这个类型,要么检查两个对象是否完全相同的类型,否则你可能会得到不对称的等式

答案 1 :(得分:0)

这是代码:

var elementsMissingFromFirstList = firstList.Except(secondList).ToList();
var elementsMissingInSecondList  = secondList.Except(firstList).ToList();

现在您可以对这些缺失的元素执行操作:)

答案 2 :(得分:0)

您可以使用此方法比较两个不同列表的对象。 exmp:列表和列表x和y = DocumentCompare,

  public static bool EqualsObject<T>(this T t1, T t2) where T : class
        {
            var p1 = t1.GetType().Fields();
            var p2 = t2.GetType().Fields();
            for (int j = 0; j < p1.Length; j++)
            {
                var x = p1[j].GetValue(t1, null);
                var y = p2[j].GetValue(t2, null);
                if (x == null && y == null)
                    continue;
                if (x != null && y == null)
                    return false;
                if (x == null)
                    return false;
                if (!x.Equals(y))
                {
                    return false;
                }
            }
            return true;
        }

此方法将显示这两个列表之间的区别。

    public static List<T> DifferentObjects<T>(List<T> t, List<T> t2) where T : class
    {
        var diff = new List<T>();
        if (t != null && t2 != null)
        {
            foreach (T t1 in t)
            {
                var state = false;
                foreach (T t3 in t2.Where(t3 => EqualsObject(t1,t3)))
                {
                    state = true;
                }
                if (!state)
                {
                    diff.Add(t1);
                }
            }
        }
        return diff;
    }

你可以这样使用代码

        var t = new List<DocumentCompare>();
        var t2 = new List<DocumentCompare>();

        t.Add(new DocumentCompare{Customer = "x"});
        t.Add(new DocumentCompare{Customer = "y"});
        t.Add(new DocumentCompare{Customer = "z"});

        t2.Add(new DocumentCompare { Customer = "t" });
        t2.Add(new DocumentCompare { Customer = "y" });
        t2.Add(new DocumentCompare { Customer = "z" });

        var list = DifferentObjects(t, t2);
        var list2 = DifferentObjects(t2, t);

您在类中使用了字段(Customer,FileName等..),因此GetType()。Fields();用于EqualsObject方法。如果你使用属性,你应该使用GetType()。Properties();在EqualsObject方法中。