首页 > 解决方案 > DataTable.Rows.Add():集合被修改;枚举操作可能无法执行

问题描述

我有一个跨不同线程共享的数据集。但是每个 DataTable 仅在特定线程上独占使用。时不时地我得到这个错误:Collection was modified; enumeration operation may not execute.

这是我的代码:

DataTable dt = null;
lock (ds)
{
    dt = ds.Tables.Add("FeedbackSummary");
}

dt.Columns.Add("FeedbackId", typeof(int));
dt.Columns.Add("Question", typeof(string));
dt.Columns.Add("Total Ratings", typeof(int));
dt.Columns.Add("Total Votes", typeof(int));

List<Feedback> feedbacks = GetFeedbacks();
foreach (Feedback f in feedbacks)
{
    int id = f.FeedbackId;
    DataRow dr = dt.Select("FeedbackId=" + id).FirstOrDefault();
    if (dr == null)
    {
        dr = dt.NewRow();
        dr["FeedbackId"] = id;
        dr["Question"] = f.Question;
        dr["Total Ratings"] = 0;
        dr["Total Votes"] = 0;
        dt.Rows.Add(dr); //error occurs here. dt.Rows.Count is 0
    }

    dr["Total Votes"] = (int)dr["Total Votes"] + f.TotalVotes;
    dr["Total Ratings"] = (int)dr["Total Ratings"] + f.TotalRating;
}

dt.Rows.Add即使 DataTable 未共享且未foreach对 DataTable 的行执行,它也会发生。更糟糕的是,它会间歇性地发生。

完整的错误(来自异常的 StackTrace):

at System.Collections.ArrayList.ArrayListEnumeratorSimple.MoveNext()
at System.Data.ConstraintEnumerator.GetNext()
at System.Data.DataTable.CascadeAll(DataRow row, DataRowAction action)
at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent)
at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Boolean suppressEnsurePropertyChanged, Int32 position, Boolean fireEvent, Exception& deferredException)
at System.Data.DataTable.InsertRow(DataRow row, Int64 proposedID, Int32 pos, Boolean fireEvent)
at System.Data.DataRowCollection.Add(DataRow row)
at Website.GenerateFeedbackSummary(DataSet ds) in C:\Pro\Website\Website\Utils\Reports.Summary.cs:line 88
at Website.ReportUtils.<>c__DisplayClass80_0.<GenerateReportSummary>b__3() in C:\Pro\Website\Website\Utils\ReportUtil.cs:line 565
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()

任何想法?

谢谢...

这是 GetFeedbacks() 的代码

using (EFOrderDB ef = DBProvider.Create())
{
    return DBProvider.GetRetryPolicy().ExecuteAction<List<Feedback>>(() =>
    {
        return (from rec in ef.Feedbacks.AsNoTracking()
                select rec).Take(20).ToList<Feedback>();
    });
}

标签: c#multithreadingdatatable

解决方案


推荐阅读