簡體   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