2

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; }
}
Arti
  • 2,993
  • 11
  • 68
  • 121

2 Answers2

2

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
}
Pradeep Kumar
  • 6,836
  • 4
  • 21
  • 47
0

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.

George Polevoy
  • 7,450
  • 3
  • 36
  • 61