John Bergqvist John Bergqvist - 2 months ago 7
C# Question

List.Contains not working when interating through a foreach loop

I have an list of FilterItems (called filter). Each FilterItem consists of a string & a boolean value. e.g. "0" and false.

I have declared the list like so:

List<FilterItem> filter = new List<FilterItem>();


I'm then iterating through a datatable column, the intention is to add every single value from that column into filter - and if a value occurs twice - don't add a repeat entry to the filter List. This is what i'm doing:

List<FilterItem> filter = new List<FilterItem>(); //initialise new list
foreach (DataRow row in RawResults.Rows) //For each row in DT
{
FilterItem myItem = new FilterItem { Name = row.ItemArray[i].ToString(), Checked = CheckState.Checked }; //create item
if (!filter.Contains(myItem)) //if item doesn't exist
{
filter.Add(myItem); //add it
}
}


The problem is that the result of Contains is always false even when myItem is identical to items already in the list - I think this is beacuse of the foreach loop - but I don't understand why because the filter List is declared outside of that loop. I've tried declaring myItem outside of the foreach loop too and that makes zero difference.

If I do the following:

List<FilterItem> filter = new List<FilterItem>(); //initialise new list
foreach (DataRow row in RawResults.Rows) //For each row in DT
{
FilterItem myItem = new FilterItem { Name = row.ItemArray[i].ToString(), Checked = CheckState.Checked }; //create item
if (!filter.Contains(myItem)) //if item doesn't exist
{
filter.Add(myItem); //add it
}
FilterItem myItem = new FilterItem { Name = row.ItemArray[i].ToString(), Checked = CheckState.Checked }; //create item
if (!filter.Contains(myItem)) //if item doesn't exist
{
filter.Add(myItem); //add it
}
}


The 2nd time .Contains is called (within the same iteration of the foreach loop) it correctly goes to true, just not when the foreach loop is iterated around again.

Answer

'The problem is that the result of Contained is always false even when myItem is identical to items already in the list ' In fact it's not - you are always instantiating new objects and .Contains method only compares the references. The best way to do in here is to check if there is already an item on the list with the same set of properties:

!filter.Any(item => item.Name == myItem.Namae && item.Checked == myItem.Checked);

Should do the trick, cause you are comparing not the references but actual properties of an item.