BOR15K
BOR15K

Reputation: 468

C# List<Object>.Equals fails on object comparison

I have a class as below. To an object of this class I need to add a new language in case it doesn't exist

using System;
using System.Collections.Generic;
namespace discovery.POCO
{
    public class MultiLingualObject 
    {
        public string TableName { get; set; }
        public string BranchId { get; set; }
        public int    GenericId { get; set; }
        public string GenericCode { get; set; }
        public List<MultiLingualColumn> MultiLingColumnsCollection = new List<MultiLingualColumn>();
    }
    public class MultiLingualColumn : IEquatable<MultiLingualColumn>
    {
        public string ColumnName { get; set; }
        public string LanguageCode { get; set; }
        public string LanguageText { get; set; }

        public bool Equals(MultiLingualColumn other)
        {
            if (other == null) return false;
            return  string.Equals(ColumnName,other.ColumnName) &&
                    string.Equals(LanguageCode, other.LanguageCode) &&
                    string.Equals(LanguageText, other.LanguageText);
        }
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != GetType()) return false;
            return Equals(obj as MultiLingualColumn);
        }
    }

}

As I am new to C# I have searched for various solutions, including .Contains or Equal (from where I have added override to my Equal above). I also understand I can achieve the comparison by simply using where like this. Yet, as I might have more elements added to the class, I would like to stick to either Equal or Contains, if possible. The code I use to compare and then to insert if doesn't exist is as following

internal void UpdateLocalMultiLing()
        {
            POCO.MultiLingualColumn _equals = new POCO.MultiLingualColumn()
            {
                ColumnName = InvoiceComment.Name.TrimEnd(),
                LanguageCode = inputLanguage,
                LanguageText = InvoiceComment.Value.TrimEnd()
            };

            if (!SupplierMultiLing.MultiLingColumnsCollection.Equals(_equals))
                SupplierMultiLing.MultiLingColumnsCollection.Add(new POCO.MultiLingualColumn
                {
                    ColumnName   = InvoiceComment.Name.Trim(),
                    LanguageCode = inputLanguage,
                    LanguageText = InvoiceComment.Value.Trim()
                }
                );
        }

yet it ignores the condition and adds the same language again. It can be seen from the image attached.enter image description here

Can one advise what shall I fix, please?

Upvotes: 1

Views: 1607

Answers (2)

smolchanovsky
smolchanovsky

Reputation: 1863

You should use the Contains() method. Also you should implement IEquatable interface for the MultiLingualColumn or implement IEqualityComparer and pass the second argument to Contains(). I prefer the second option:

public class MultiLingualColumnComparer : IEqualityComparer<MultiLingualColumn>
{
    public bool Equals(MultiLingualColumn x, MultiLingualColumn y)
    {
        //...
    }

    public int GetHashCode(MultiLingualColumn obj)
    {
        //...
    }
}

and then:

if (!SupplierMultiLing.MultiLingColumnsCollection.Contains(_equals, new MultiLingualColumnComparer()))

Upvotes: 0

CodeCaster
CodeCaster

Reputation: 151594

You're comparing a list against a single object. You need .Contains() instead of .Equals().

Either properly implement IEquatable<T>, or override Equals(object) and GetHashCode(). From What does Collection.Contains() use to check for existing objects?:

either implement IEquatable on your custom class, or override the Equals (and GetHashCode)

This code prints "True":

public class Foo : IEquatable<Foo>
{
    public string Bar { get; set; }

    public bool Equals(Foo other)
    {
        return other.Bar == this.Bar;
    }
}

public static void Main()
{
    var list = new List<Foo>
    {
        new Foo { Bar = "Baz" }
    };

    Console.WriteLine(list.Contains(new Foo { Bar = "Baz" }));
}

But as @Jeppe correctly comments, it's advisable to also provide a proper implementation of GetHashCode() for other collection and comparison types.

Upvotes: 4

Related Questions