0

I have a class with 2 properties

public class SampleClass
{
    public string Name { get; set; }
    public List<Component> Components { get; set; }
}

And another class which is hold some string properties.

public class Component
{
    public string Name { get; set; }
    public string Age{ get; set; }
}

I have instance of this class created and added into a List

SampleClass classWithValues = new SampleClass();
var listComponent = new List<Component>();
listComponent.add(new Component{Name = "Random string",Age = "31"})
classWithValues.Components = listComponent; 
classWithValues.Name = "TestName"

var listWithObjectClass = new List<SampleClass>();
listWithObjectClass.add(classWithValues);

Then i made a new instance of the SampleClass class and add exactly the same value into the properties :

SampleClass classWithValues1 = new SampleClass();
var listComponent1 = new List<Component>();
listComponent1.add(new Component{Name = "Random string",Age = "31"})
classWithValues1.Components = listComponent1; 
classWithValues1.Name = "TestName";

And here is coming the strange part : if I compare the property Names inside the list with the second instance of the Sample class with the new instance of the same class:

 bool alreadyExists = listWithObjectClass.Any(x => x.Name == classWithValues1 .Name);

the result is true BUT if I compare the List properties

 bool alreadyExists = listWithObjectClass.Any(x => x.Components == classWithValues1.Components);

the result is false ?! Can someone please give some information about this behavior.

NDym
  • 79
  • 12

2 Answers2

0

The first comparison is about comparing the value of the two string. However, the second comparison is about Comparing two different object which their reference are different. Indeed, for the second comparison, compare their hashCode. To watch this, you can call .GetHashCode() for these two objects.

 listComponent.GetHashCode() == listComponent1.GetHashCode() // false
 listComponent[0].GetHashCode() == listComponent1[0].GetHashCode() // false
OmG
  • 18,337
  • 10
  • 57
  • 90
  • 1
    Ok but how to make the "right" comparing of the object then in order to get true result if the object are the same ? – NDym May 11 '17 at 12:16
  • The right comparison is comparing these fields member by member. Also, there are different techniques to do this in a clean form. For example, you can see this post: http://stackoverflow.com/questions/10454519/best-way-to-compare-two-complex-object – OmG May 11 '17 at 12:22
  • Remember that hash codes only tell you that 2 objects are definitely different if they don't match... You can't infer equality (or anything) from matching hashcodes. I learnt this the hard way and trust me, ignoring this can cause some difficult to debug malfunctions. – Leo May 11 '17 at 12:39
  • 1
    @LeonardoSeccia You're right. However, the same referenced object, must have the same hash code, not vice versa. – OmG May 11 '17 at 13:20
  • @OmG: that's true, so if hash codes match, I would then proceed to do a more deep equality comparison. On the other hand if they don't match, I know they are definitely different. – Leo May 11 '17 at 13:39
0

Sorry my first answer was not quite right...

In order to get alreadyExist to be true you need to put in place property comparison in your classes as otherwise the equality comparison performed is the default reference comparison. Your objects contains the same property values but are actually different instances... The default equality comparison for objects is comparing references not content.

Try this...

void Main()
{
    SampleClass classWithValues = new SampleClass();
    var listComponent = new Components();
    listComponent.Add(new Component{Name = "Random string",Age = "31"});
    classWithValues.Components = listComponent; 
    classWithValues.Name = "TestName";

    var listWithObjectClass = new List<SampleClass>();
    listWithObjectClass.Add(classWithValues);

    SampleClass classWithValues1 = new SampleClass();
    var listComponent1 = new Components();
    listComponent1.Add(new Component{Name = "Random string",Age = "31"});
    classWithValues1.Components = listComponent1; 
    classWithValues1.Name = "TestName";

    bool alreadyExists = listWithObjectClass.Any(x => x.Components.Equals(classWithValues1.Components));
}

public class SampleClass
{
    public string Name { get; set; }
    public Components Components { get; set; }
}

public class Component : IEquatable<Component>
{
    public string Name { get; set; }
    public string Age{ get; set; }

    public bool Equals(Component otherComponent)
    {
        return Name == otherComponent.Name && Age == otherComponent.Age;
    }
}

public class Components :List<Component>, IEquatable<Components>
{
    public bool Equals(Components otherComponents)
    {
        if(this.Count!= otherComponents.Count) return false;

        return this.TrueForAll(a=> otherComponents.Any(q=>q.Equals(a)))
        && otherComponents.TrueForAll(a=> this.Any(q=>q.Equals(a)));
    }
}
Leo
  • 5,013
  • 1
  • 28
  • 65
  • there are also other options such as serializing both objects and compare the resulting strings or using reflection to compare objects properties – Leo May 11 '17 at 12:36