比较两个复杂列表对象[英] Compare two complex list objects

本文是小编为大家收集整理的关于比较两个复杂列表对象的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

如何检查两个对象列表是否相同?我的列表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

在这里,两个列表都不相同(备注字段).我想要一个代码,该代码将比较这两个列表并返回相同的代码.我该怎么做?

我尝试使用List1.Except(List2),但没有比较.

编辑

我创建了Custom 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; }
}

推荐答案

首先修改您的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
}

其他推荐答案

您的问题是内部类没有平等操作员超载==.

例如,x.Details == y.Details始终返回false,无论该实例存在哪个数据,因为默认==运算符只是调用equals方法,该方法会导致参考平等,如object.Equals方法所定义.

请参阅 for equals()和操作员的指南==(C#编程指南)

另外,GethashCode方法中也存在错误.切勿使用字符串串联计算哈希码.另外,您的ToString方法不超载,因此它只是返回相同的默认字符串,该字符串对于哈希代码计算无用.

本文地址:https://www.itbaoku.cn/post/1556741.html

问题描述

How to check if two list of objects are same? I have list A and list B with same structure:

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

I convert it to list using linq.

List A:

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

List B:

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

Here both the lists are not same(remarkText field). I want a piece of code which will compare these two list and return whether same or no. How can i do that?

I tried using List1.Except(List2) but it doesn't compare.

Edit

I have created custom 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();
    }
}

And

var Comparer = new Compare(); List1.Except(List2, Comparer) Should this work?

Edit

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

推荐答案

First modify your test class and implement (override) the Equals function. This will give you class the ability to compare itself with another object and tell whether both are same or not.

Ideally, each of your class should have its own Equals implementation, and the parent class should have no business of comparing the internals of child objects. But seeing that you need to compare only your test class, we implement all the comparison logic in the test class itself.

[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();
    }
}

Then you can easily compare two objects of your test class easily.

e.g.

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
}

其他推荐答案

Your problem is that the inner classes do not have equality operator overloads ==.

For example, x.Details == y.Details always returns false, no matter which data the instances hold, because the default == operator just calls the Equals method, which results in a reference equality, as defined in object.Equals method.

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

Also, there is an error in GetHashCode method. Never compute the hash codes with string concatenation. In addition, your don't overload the ToString method, so it just returns the same default string which is not useful for hash code computation.