user2865446
user2865446

Reputation: 633

C# contains behaviour

Can someone please explain why these two methods are returning different values?

List<CustomerSummary> summaries = new List<CustomerSummary>();

for (var i = 0; i < 10; i++)
{

var summary = new CustomerSummary() { ID = 1, Name = "foo", balance = 50.00 };

if (!summaries.Contains(summary))
    summaries.Add(summary);

}

-

List<CustomerSummary> summaries = new List<CustomerSummary>();

for (var i = 0; i < 10; i++)
{

 var summary = new CustomerSummary() { ID = 1, Name = "foo", balance = 50.00 };

 if (!summaries.Any(s=> s.ID == summary.ID))
     summaries.Add(summary);

}

The first method has 10 items in the list while the second has 1. Why does the first ( Contains() ) method never evaluate as true?

What I'm trying to ask is why are 2 objects of the same type with the same values for each property not evaluating as equivalent (in the first method)?

Upvotes: 6

Views: 240

Answers (5)

Chamika Sandamal
Chamika Sandamal

Reputation: 24302

List<T>.Contains method determines equality by using the default equality comparer. And here you are trying to compare two different objects. Both may have all the properties filled with matching values, but those are two different objects. If you want to really use the Contains method here, you have to implement the IEquatable<T>.Equals method in your CustomerSummary object.

Upvotes: 2

Grant Winney
Grant Winney

Reputation: 66479

Your first block of code is creating a new instance inside the loop, and then immediately checking to see if that exact instance is already in the collection. It can't be - you just created it.

You might as well write it like this:

List<CustomerSummary> summaries = new List<CustomerSummary>();

for (var i = 0; i < 10; i++)
{
    var summary = new CustomerSummary { ID = 1, Name = "foo", balance = 50.00 };

    summaries.Add(summary);
}

Your second block of code is checking for the existence of any item in the collection with a matching ID. Since you've hard-coded the ID to be 1, you're only going to add an item the first time around. Every instance created after that will return false in the if statement, and will not be added.

You could change that behavior by changing the ID:

for (var i = 0; i < 10; i++)
{
    var summary = new CustomerSummary { ID = i, Name = "foo", balance = 50.00 };

    if (!summaries.Any(s=> s.ID == summary.ID))
        summaries.Add(summary);
}

Again, the if statement is no longer even necessary, since you know the ID can't possibly already exist in the collection, so you could just remove the check.

Upvotes: 3

bit
bit

Reputation: 4487

That's because Contains() matches the reference of the Summary .. and not the ID.

Every time you do a

var summary = new CustomerSummary() { ID = 1, Name = "foo", balance = 50.00 };

in your loop, you create a new instance of CustomerSummary and hence a new reference is stored in summary, thought the values of every property within the CustomerSummary asre exactly same..

Upvotes: 2

Max
Max

Reputation: 156

hi in the first function you trying to use contains on the entire object and not on property like you do in the second function try change first like this

 List<CustomerSummary> summaries = new List<CustomerSummary>();

        for (var i = 0; i < 10; i++)
        {

            var summary = new CustomerSummary() { ID = 1, Name = "foo", balance = 50.00 };

            if (!summaries.Select(s=>s.ID).Contains(summary.ID))
                summaries.Add(summary);

        }

Upvotes: 1

Sourabh Sharma
Sourabh Sharma

Reputation: 8322

if (!summaries.Contains(summary))

This will check whole touple(row)

 { ID = 1, Name = "foo", balance = 50.00 }

And

This will check single element Id=1.

Upvotes: 0

Related Questions