Unhandled exception has occurred. 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.WhereSelectListIterator`2.MoveNext()
at System.Linq.Enumerable.Sum(IEnumerable`1 source)
at Check.get_TotalChange()
at CheckChanged(ICheck check)
如果我每天运行我的代码 5000 次,比如 2 次,它将导致此错误并且程序将崩溃。我的代码有什么问题?我按照异常信息,我认为这是可能导致异常的代码。任何人都知道这是什么类型的问题?
public decimal TotalChange
{
get
{
var change = (from IPayment payment in _payments where payment.Amount < 0 select payment.Amount).Sum();
var paid = (from IPayment payment in _payments select payment.Amount).Sum();
return paid <= Total && Total > 0 ? Math.Abs(change) : paid - Total;
}
}
我把它改成:
private readonly object _totalChangeLock = new object();
public decimal TotalChange
{
get
{
lock (_totalChangeLock)
{
var change =
(from IPayment payment in _payments where payment.Amount < 0 select payment.Amount).Sum();
var paid = (from IPayment payment in _payments select payment.Amount).Sum();
return paid <= Total ? Math.Abs(change) : paid - Total;
}
}
}
此外,我还有 2 种修改 _payments 的方法。我也锁了他们。希望不会造成任何问题。
public void AddPayment(IPayment payment)
{
lock (_paymentsLock)
{
if (_payments.Contains(payment)) return;
_payments.Add(payment);
}
}
public void RemovePayment(IPayment payment)
{
lock (_paymentsLock)
{
if (_payments.Contains(payment))
_payments.Remove(payment);
}
}
请您参考如下方法:
很可能您在执行 TotalChange 属性代码时从另一个线程修改了 _payments 变量。
如果这是真的,请尝试避免多线程访问 _payments 变量或考虑在对 _payments 变量进行读/写访问时使用锁定
lock(_lockerObject)
{
// Do operations that modify _payments collection
_payments.Add();//...
}
public decimal TotalChange
{
get
{
lock (_lockerObject)
{
var change = (from IPayment payment in _payments where payment.Amount < 0 select payment.Amount).Sum();
var paid = (from IPayment payment in _payments select payment.Amount).Sum();
}
return paid <= Total && Total > 0 ? Math.Abs(change) : paid - Total;
}
}
