Я работаю с приложением .NET WinForms на С#, работающим с 3.5.NET framework. В этом приложении я устанавливаю элемент .Expression DataColumn
в DataTable
, например:
DataColumn column = dtData.Columns["TestColumn"];
column.Expression = "some expression";
Вторая строка, на которой я фактически устанавливаю Expression
, иногда приводит к следующему исключению:
FileName=
LineNumber=0
Source=System.Data
TargetSite=Int32 RBInsert(Int32, Int32, Int32, Int32, Boolean)
System.InvalidOperationException: DataTable internal index is corrupted: '5'.
at System.Data.RBTree`1.RBInsert(Int32 root_id, Int32 x_id, Int32 mainTreeNodeID, Int32 position, Boolean append)
at System.Data.RBTree`1.RBInsert(Int32 root_id, Int32 x_id, Int32 mainTreeNodeID, Int32 position, Boolean append)
at System.Data.Index.InitRecords(IFilter filter)
at System.Data.Index.Reset()
at System.Data.DataTable.ResetInternalIndexes(DataColumn column)
at System.Data.DataTable.EvaluateExpressions(DataColumn column)
at System.Data.DataColumn.set_Expression(String value)
Нет заметной рифмы или причины того, когда произойдет ошибка; при загрузке одного и того же набора данных он может работать нормально, но при перезагрузке он не удастся, и наоборот. Это заставляет меня думать, что это связано с состоянием гонки, где другая операция записи происходит на DataTable
, поскольку я пытаюсь изменить один из его столбцов. Однако код, относящийся к DataTable
, не является многопоточным и работает только в потоке пользовательского интерфейса.
Я искал в Интернете и форумы Microsoft, и есть много дискуссий и путаницы по этой проблеме. Назад, когда проблема впервые появилась в 2006 году, была мысль о том, что это был недостаток в платформе .NET, и были выпущены некоторые предполагаемые исправления, которые предположительно были перенесены в более поздние версии платформы .NET. Тем не менее, люди сообщают о смешанных результатах применения этих исправлений, которые больше не применимы к текущей структуре.
Другая распространенная теория заключается в том, что в DataTable есть операции, которые, хотя кажутся безобидными, на самом деле являются операциями записи. Например, создание новой DataView
на основе DataTable
на самом деле является операцией записи в самой таблице, поскольку она создает внутренний индекс в DataTable
для последующей ссылки. Эти операции записи не являются потокобезопасными, поэтому иногда случается, что условие гонки приводит к записи без прочтения, совпадающей с нашим доступом к DataTable
. Это, в свою очередь, приводит к повреждению внутреннего индекса DataTable
, что приводит к исключению.
Я попытался помещать lock
блоки вокруг каждого создания DataView
в коде, но, как я уже упоминал ранее, код, использующий DataTable
, не имеет резьбы, а lock
не имеет никакого эффекта, в любом случае.
Кто-нибудь видел это и успешно решил/работал вокруг него?
Нет, к сожалению, я не могу. Загрузка DataTable уже произошла к тому моменту, когда я удержал его, чтобы применить выражение к одному из его DataColumn. Я мог бы удалить столбец, а затем снова добавить его с помощью кода, который вы предложили, но есть ли какая-то особая причина, почему это может решить внутренний индекс - это проблема с повреждением?