Foreach循环遍历列表的错误

时间:2012-06-12 22:40:37

标签: c# list foreach invalidoperationexception argumentexception

我有以下代码给我提出问题,我将不胜感激:

private static string CreateOptionString(List<VehicleOption> Options)
{
    StringBuilder returnValue = new StringBuilder();
    foreach (VehicleOption option in Options)
    {
        if (option.OptionStatus == ExtendedResponse.OptionState.Included)
        {
            if (returnValue.Length > 0)
            {
                returnValue.Append(", ");
            }
            returnValue.Append(option.OptionName);
        }
    }
    return returnValue.ToString();
}

我最初的问题是我收到了一个System.InvalidOperationException:我的foreach循环上的集合被修改了错误。

1)我仍然无法弄清楚为什么我会收到此错误,因为我没有看到它被修改的任何地方。

有人建议我将List复制到新列表并循环遍历新列表。我做到了,它摆脱了InvalidOperationException。但是,我试着以不同的方式处理列表,并且两者都给了我一个System.ArgumentException:目标数组不够长。 以下是我尝试复制列表的两种方法

List<VehicleOption> newOptions = new List<VehicleOption>(Options);

List<VehicleOption> newOptions = new List<VehicleOption>();
newOptions.AddRange(Options);

这两个都给了我一个System.ArgumentException:Destination数组不够长。

2)为什么这些方法都会给我这个例外?

任何帮助都会受到赞赏,因为我很难过。

谢谢!

3 个答案:

答案 0 :(得分:5)

确保在迭代过程中没有其他线程正在更改集合。

另外,另一种方法是:

return string.Join(", ", options.Where(
    op => op.OptionStatus == ExtendedResponse.OptionState.Included));

在这种情况下,哪个更好(并且令人惊讶地)比使用StringBuilder更快。

尽管如此,这并不能解决您的问题 - 这可能是由更改集合的不同线程引起的。

我的第一次尝试是:

private static string CreateOptionString(List<VehicleOption> Options)
{
    lock (Options)
    {
        return string.Join(", ", options.Where(
            op => op.OptionStatus == ExtendedResponse.OptionState.Included));
    }
}

但是,当然,如果我们有关于该集合的其他线程的任何信息,那么提供更好的线程安全解决方案会更容易。

答案 1 :(得分:4)

听起来Options引用的列表对象正被另一个线程更改。这可以解释这两个问题。

  1. 显然,如果另一个线程在迭代时更改了列表,您会看到“集合被修改”异常,因为在枚举其元素时无法更改列表。
  2. 在后一种情况下,听起来像构造函数和AddRange正在分配数组,然后从提供的可枚举中填充它。如果列表在分配和枚举之间增长以填充新数组,则突然分配的存储空间不够大,您会看到此行为。
  3. 您需要设计一些锁定机制,以便此代码可以阻止可能在处理元素时写入列表的任何线程,或者制作副本以便稍后处理。

答案 2 :(得分:0)

好的,我最终解决了这个问题。我在方法调用周围放了一个锁(在选项列表上)。这解决了我的所有问题。

感谢所有人!