繁体   English   中英

奇怪的“Collection was modified”异常,尽管它从未被修改过

[英]Strange `Collection was modified` exception though it never gets modified

如果我有一个预定义的集合并且它的值仅通过索引访问和更新,为什么我会得到Collection was modified异常。 没有线程向集合中删除或添加项目。 异常发生在行var values = new List<double> { amount.Values[0], amount.Values[1] };

System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
   at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
   at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
   at System.Collections.Generic.List`1.Enumerator.MoveNext()
   at System.Linq.Enumerable.<SkipIterator>d__31`1.MoveNext()
   at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)
   at MyProject.Exensions.ToFixed(Amount amount) in ...\Amount.cs:line 43 ...

代码

private List<double> _currentAmount = new List<double>(...);
public async Task<Amount> GetAmount(bool fromCache = true)
{
   if(!fromCache)
   {
       _currentAmount = await _service.GetAmount(); 
   }
   
   return new Amount(_currentAmount).ToFixed(); 
}

// Called every 100ms by other thread
private void OnAmountChanged(AmountChangedEventArgs args)
{
    _currentAmount[args.Index] = args.Value;
    AmountChanged?.Invoke(new Amount(_currentAmount));
}

public static Amount ToFixed(this Amount amount)
{
    var values = new List<double> { amount.Values[0], amount.Values[1] };
    values.Add(amount.Values[2] * 0.1);
    values.AddRange(amount.Values.Skip(3));

    return new Amount(values);
}

public sealed class Amount
{
    public ReadOnlyCollection<double> Values { get; }

    public Amount(IList<double> values)
    {
        Values = new ReadOnlyCollection<double>(values);
    }
    
    ...
}

您正在通过修改列表使迭代器无效。 在评论中,你说:

但是“更改集合”仅表示添加或删除项目时,而不是索引修改值时,不是吗?

但不,这不是它的意思。 List<T>.GetEnumerator的文档(强调我的):

只要集合保持不变,枚举器就一直有效。 如果对集合进行了更改,例如添加、修改或删除元素,则枚举器将不可恢复地失效,并且下一次调用MoveNextIEnumerator.Reset将引发InvalidOperationException

这很容易在一个最小的例子中证明:

using System;
using System.Collections.Generic;
using System.Linq;

var list = new List<int> { 0, 1, 2 };
foreach (var element in list)
{
    list[1] = 5;
}

这会引发InvalidOperationException异常,这与您的预期相反。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM