【问题标题】:List.Contains not working when interating through a foreach loopList.Contains 在遍历 foreach 循环时不起作用
【发布时间】:2017-02-03 17:38:16
【问题描述】:

我有一个 FilterItems 列表(称为过滤器)。每个 FilterItem 由一个字符串和一个布尔值组成。例如“0”和假。

我已经这样声明了列表:

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

然后我将遍历数据表列,目的是将该列中的每个值添加到过滤器中 - 如果一个值出现两次 - 不要将重复条目添加到过滤器列表中。这就是我正在做的:

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
    }
}

问题在于,即使 myItem 与列表中已有的项目相同, Contains 的结果也始终为 false - 我认为这是因为 foreach 循环 - 但我不明白为什么,因为过滤器 List 是在外部声明的那个循环。我也尝试在 foreach 循环之外声明 myItem ,这使差异为零。

如果我执行以下操作:

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
    }
}

第二次 .Contains 被调用(在 foreach 循环的同一迭代中)它正确地变为 true,而不是在 foreach 循环再次迭代时。

【问题讨论】:

  • 显示FilterItem 的代码。我的猜测是它不会覆盖EqualsGetHashCode,这意味着Contains 将执行引用相等而不是值相等。

标签: c# list foreach contains


【解决方案1】:

'问题在于,即使 myItem 与列表中已有的项目相同,Contained 的结果也始终为 false ' 事实上不是——你总是在实例化新对象,而 .Contains 方法只比较引用。 最好的方法是检查列表中是否已经存在具有相同属性集的项目:

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

应该做到这一点,因为您比较的不是参考而是项目的实际属性。

【讨论】:

    【解决方案2】:

    根据this 线程,.Contains() 使用默认的IEqualityComparer 作为类,因此,在大多数情况下,它会将引用与对象进行比较。

    为了检查元素是否确实包含,您需要使用.Any() 或实现自己的相等比较器。

    【讨论】:

      【解决方案3】:

      代码new FilerItem 正是这样做的,它创建了一个新的过滤器项。这个新项目不同于任何其他对象,即使属性完全相同,它也是一个不同的实例。

      如果您将第一个 if 语句更改为:

      if(!filter.Any(i => i.Name == myItem.Name && i.Checked == myItem.Checked)) { //...
      

      您将实际比较属性。或者,您可以覆盖 FilterItem 类中的 Equals 方法或实现 IEquatable&lt;T&gt;

      【讨论】:

        【解决方案4】:

        您应该考虑在 FilterItem 类中覆盖 Equals 和 GetHashCode 方法。这样,根据用于存储 FilterItem 实例的集合,在对该特定集合调用 Add/Contains 方法时将触发相应的方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-02-04
          • 2019-02-18
          • 1970-01-01
          • 1970-01-01
          • 2013-12-16
          • 2018-09-15
          • 2013-03-17
          • 1970-01-01
          相关资源
          最近更新 更多