Today I encountered InvalidOperationException when Unity was running: Collection was modified; enumeration operation may not execute.
After opening the code, I found that the Dictionary data structure was used, but it was not modified in the foreach loop, it was just called in Update.
foreach (var item in statusTimers)
{
var status = item.Key;
statusTimers[status] -= deltaTime;
if (statusTimers[status] <= 0f)
{
if (statusesToRemove == null)
{
statusesToRemove = new Dictionary<CharacterStatusType, float>();
}
statusesToRemove.Add(status, statusTimers[status]);
}
}
After carefully checking multiple files, I called an add method in a Ctrip. This method added to the Dictionary. At this time, Update on the other side was in the middle of a foreach traversal, so a conflict occurred and an error occurred.
private IEnumerator CastRoutine()
{
// ...
target._stateManager.AddStatus(_addStatus, _statusTime);
}
public void AddStatus(CharacterStatusType status, float duration)
{
if (!statusTimers.ContainsKey(status))
{
statusTimers.Add(status, duration);
UpdateCurrentStatus();
}
else
{
// 如果已存在该异常状态,保留较长的持续时间
float existingDuration = statusTimers[status];
statusTimers[status] = Mathf.Max(existingDuration, duration);
UpdateCurrentStatus();
}
}
Solution: Unity provides a thread-safe collection class ConcurrentDictionary, which can correctly handle concurrent access to the dictionary in Ctrip. Just replace Dictionary.