【问题标题】:Compare two complex list objects比较两个复杂的列表对象
【发布时间】:2016-05-04 20:33:19
【问题描述】:

如何检查两个对象列表是否相同?我有具有相同结构的列表 A 和列表 B:

[XmlRoot(ElementName = "Details")]
public class Details
{
    [XmlElement(ElementName = "time")]
    public string time { get; set; }
    [XmlElement(ElementName = "duration")]
    public string duration { get; set; }
}

[XmlRoot(ElementName = "Remark")]
public class Remark
{
    [XmlElement(ElementName = "RemarkText")]
    public string RemarkText { get; set; }
    [XmlElement(ElementName = "isRemarkVisible")]
    public Boolean IsRemarkVisible { get; set; }
}

[XmlRoot(ElementName = "test")]
public class test
{
    [XmlElement(ElementName = "ID")]
    public string ID { get; set; }
    [XmlElement(ElementName = "Name")]
    public string Name { get; set; }
    public Details Details { get; set; }
    [XmlElement(ElementName = "Remark")]
    public Remark Remark { get; set; }
}

[XmlRoot(ElementName = "Tests")]
public class Tests
{
    [XmlElement(ElementName = "test")]
    public test[] test { get; set; }
}

我使用 linq 将其转换为列表。

列表 A:

Test
id=1
name=abc
details
    starttime=9.00
    endtime=12.00
    duration=1hr
Remark
    RemarkText= remark1 
    IsRemarkVisible=true

列表 B:

Test
id=1
name=abc
details
    starttime=9.00
    endtime=12.00
    duration=1hr
Remark
    RemarkText= remark2 
    IsRemarkVisible=true

这两个列表不相同(remarkText 字段)。我想要一段代码来比较这两个列表并返回是否相同。我该怎么做?

我尝试使用List1.Except(List2),但无法比较。

编辑

我创建了自定义 IEqualityComparer:

public class Compare : IEqualityComparer<test>
{
    public bool Equals(test x, test y)
    {
        if (x == null || y == null) return false;

        bool equals = x.ID == y.ID && x.Name == y.Name && x.Remark == y.Remark
            && x.Details == y.Details;
        return equals;
    }
    public int GetHashCode(test codeh)
    {
        return (codeh.ID + codeh.Name + codeh.Remark + codeh.Details).GetHashCode();
    }
}

还有

var Comparer = new Compare(); List1.Except(List2, Comparer)这应该行吗?

编辑

[XmlRoot(ElementName = "Details")]
public class Details
{
    [XmlElement(ElementName = "starttime")]
    public string starttime { get; set; }
    [XmlElement(ElementName = "endtime")]
    public string endtime { get; set; }
    [XmlElement(ElementName = "duration")]
    public string duration { get; set; }
}

[XmlRoot(ElementName = "Remark")]
public class Remark
{
    [XmlElement(ElementName = "RemarkText")]
    public string RemarkText { get; set; }
    [XmlElement(ElementName = "isRemarkVisible")]
    public Boolean IsRemarkVisible { get; set; }
}

[XmlRoot(ElementName = "test")]
public class test
{
    [XmlElement(ElementName = "ID")]
    public string ID { get; set; }
    [XmlElement(ElementName = "Name")]
    public string Name { get; set; }
    public Details Details { get; set; }
    [XmlElement(ElementName = "Remark")]
    public Remark Remark { get; set; }
    [XmlElement(ElementName = "Tags")]
    public Tags Tags { get; set; }
}

[XmlRoot(ElementName = "Tags")]
public class Tags
{
    [XmlElement(ElementName = "TagLocation")]
    public TagLocation[] TagLocation { get; set; }
}

[XmlRoot(ElementName = "TagLocation")]
public class TagLocation
{
    [XmlElement(ElementName = "Id")]
    public string Id { get; set; }
    [XmlElement(ElementName = "TagText")]
    public string TagText { get; set; }
}

[XmlRoot(ElementName = "Tests")]
public class Tests
{
    [XmlElement(ElementName = "test")]
    public test[] test { get; set; }
}

【问题讨论】:

  • 两个对象何时相等?通常实现自定义IEqualityComparer&lt;YourType&gt; 并将其传递给Except
  • 如果两个对象具有相同的数据。在我的示例中,如果列表 B 有 remarkText= remark1
  • @TimSchmelter 请您提供一个如何完成的示例。
  • 创建一个实例并传递:List1.Except(List2, yourComparer)

标签: c# linq


【解决方案1】:

首先修改您的test 类并实现(覆盖)Equals 函数。这将使您的班级能够将自己与另一个对象进行比较并判断两者是否相同。

理想情况下,每个类都应该有自己的Equals 实现,并且父类不应该比较子对象的内部结构。但是看到您只需要比较您的test 类,我们在test 类本身中实现了所有比较逻辑。

[XmlRoot(ElementName = "test")]
public class test
{
    [XmlElement(ElementName = "ID")]
    public string ID { get; set; }
    [XmlElement(ElementName = "Name")]
    public string Name { get; set; }
    public Details Details { get; set; }
    [XmlElement(ElementName = "Remark")]
    public Remark Remark { get; set; }
    [XmlElement(ElementName = "Tags")]
    public Tags Tags { get; set; }

    // override object.Equals
    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType()) return false;

        // modify the code below to suit your needs...
        test objA = (test)obj;
        if (
                this.ID != objA.ID || this.Name != objA.Name
                || this.Details.duration != objA.Details.duration || this.Details.starttime != objA.Details.starttime || this.Details.endtime != objA.Details.endtime
                || this.Remark.IsRemarkVisible != objA.Remark.IsRemarkVisible || this.Remark.RemarkText != objA.Remark.RemarkText
            ) return false;
        if (this.Tags.TagLocation.Length != objA.Tags.TagLocation.Length) return false;
        for (int i = 0; i < this.Tags.TagLocation.Length; i++)
        {
            if (this.Tags.TagLocation[i].Id != objA.Tags.TagLocation[i].Id || this.Tags.TagLocation[i].TagText != objA.Tags.TagLocation[i].TagText) return false;
        }
        return true;    // if everything matched we infer that the objects are equal.
    }

    // override object.GetHashCode
    public override int GetHashCode()
    {
        // modify the code below to generate a unique hash code for your object.
        return base.GetHashCode();
    }
}

然后您可以轻松地比较测试类的两个对象。

例如

private void button1_Click(object sender, EventArgs e)
{

    test test1, test2, test3;

    test1 = new test { ID="1", Name ="abc"};
    test1.Details = new Details { duration = "1", starttime = "9.00", endtime = "12.00" };
    test1.Remark = new Remark { IsRemarkVisible = true, RemarkText = "remark1" };
    test1.Tags = new Tags();
    test1.Tags.TagLocation = new TagLocation[] 
    { 
         new TagLocation{ Id = "1", TagText = "tag1" },
         new TagLocation{ Id = "2", TagText = "tag2" } 
    }; 

    test2 = new test { ID = "1", Name = "abc" };
    test2.Details = new Details { duration = "1", starttime = "9.00", endtime = "12.00" };
    test2.Remark = new Remark { IsRemarkVisible = true, RemarkText = "remark2" };
    test2.Tags = new Tags();
    test2.Tags.TagLocation = new TagLocation[] 
    { 
         new TagLocation{ Id = "1", TagText = "tag1" },
         new TagLocation{ Id = "2", TagText = "tag2" } 
    }; 

    test3 = new test { ID = "1", Name = "abc" };
    test3.Details = new Details { duration = "1", starttime = "9.00", endtime = "12.00" };
    test3.Remark = new Remark { IsRemarkVisible = true, RemarkText = "remark2" };
    test3.Tags = new Tags();
    test3.Tags.TagLocation = new TagLocation[] 
    { 
         new TagLocation{ Id = "1", TagText = "tag1" },
         new TagLocation{ Id = "2", TagText = "tag2" } 
    }; 

    MessageBox.Show("test1.Equals(test2) ... " + test1.Equals(test2).ToString());   // shows false
    MessageBox.Show("test2.Equals(test3) ... " + test2.Equals(test3).ToString());   // shows true
}

【讨论】:

  • 那我还需要IEqualityComparer吗?
  • 不,你没有。现在,您的类中有一个名为 Equals 的方法,您可以使用它来比较类的两个对象。
  • 我已经编辑了我的班级对象,使其具有第三级班级。那会有什么不同呢?
  • 我刚刚更新了我的答案和代码示例以满足您修改后的需求。让我知道有什么不清楚的地方。
【解决方案2】:

您的问题是内部类没有相等运算符重载==

例如,x.Details == y.Details 总是返回 false,无论实例持有哪些数据,因为默认的 == 运算符只是调用 Equals 方法,这会导致引用相等,如 object.Equals 方法中所定义.

Guidelines for Overloading Equals() and Operator == (C# Programming Guide)

另外,GetHashCode 方法也有错误。永远不要用字符串连接计算哈希码。此外,您不要重载 ToString 方法,因此它只会返回相同的默认字符串,这对于哈希码计算没有用处。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-17
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-01
    相关资源
    最近更新 更多