Я нашел это в журнале ошибок и пытаюсь понять, как это возможно. Не каждый день исключение NullReferenceException встречается глубоко внутри базовых классов .net!
1) Exception Information
*********************************************
Exception Type: System.NullReferenceException
Message: Object reference not set to an instance of an object.
Data: System.Collections.ListDictionaryInternal
TargetSite: Void Bind(System.Data.SqlClient.TdsParserStateObject)
HelpLink: NULL
Source: System.Data
StackTrace Information
*********************************************
at System.Data.SqlClient.SqlDataReader.Bind(TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult esult)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet)
at MyCode.Shared.Data.DataSocket.GetTable(String SPString)
at <rest of stack trace>
Единственное, что я могу придумать, - это (тонкий) шанс, что два потока выполняли один и тот же метод одновременно, и один очистил или изменил DataSet, который передается в Fill (). Так что мой вопрос действительно:
- как это исключение может быть выброшено
- Может ли многопоточный сценарий вызвать это исключение
- Как я могу быть уверен, например, есть ли способ пройти через методы System.Data, чтобы повторить проблему?
Между прочим, я обнаружил несколько других случаев этой проблемы, один в этом потоке, а другой в этом кеше Google чьей-либо страницы. Похоже, ни один из них не поможет.
Мой метод GetTable (), который выполняется, выглядит следующим образом:
public DataTable GetTable(string SPString)
{
//Setup the data objects by calling helper
prepareDataAdaptor(SPString,CommandType.Text);
dataAdaptor.Fill(dataSet);
dataAdaptor.SelectCommand.Connection.Close();
DataTable dt;
//ensure we dispose okay
using(dataSet)
{
if(dataSet.Tables.Count==0)
{
dataSet.Tables.Add(new DataTable("EmptyTable"));
}
dt=dataSet.Tables[0];
//because we are disposing we need to remove the table from the dataset
dataSet.Tables.Clear();
}
return dt;
}
private void prepareDataAdaptor(string SPString,CommandType Type)
{
checkForConnection();
dataSet=new DataSet();
dbCommand.CommandText=SPString;
dbCommand.CommandTimeout = MySettings.CommandTimeout;
dataAdaptor.SelectCommand=dbCommand;
dataAdaptor.SelectCommand.CommandType=Type;
dataAdaptor.SelectCommand.Connection=dbConnection;
dataAdaptor.SelectCommand.Parameters.Clear();
}
dataAdaptor (sic) - это переменная экземпляра, объявленная как IDbDataAdapter, заполненная SqlDataAdapter.
dataSet - это переменная экземпляра типа DataSet.
Моя теория гласит, что поток A проходит и частично входит в метод SqlDataAdapter.Fill (). Тем временем поток B также выполняет и делает что-то, что портит поток A, как эта строка:
dataAdaptor.SelectCommand.Connection.Close();
Я вижу, что мой код не является поточно-ориентированным, но как я могу быть уверен, что именно эта проблема вызвала указанное выше исключение?
большое спасибо за любые предложения!
Рори
РЕДАКТИРОВАТЬ: исправлен случай паршивой орфографии. Не обновлять его в коде, так как это так.
ОБНОВЛЕНИЕ: Я согласен, что в этом коде есть несколько ошибок, которые должны быть исправлены, но меня интересует, есть ли способ проверить, что именно эта проблема с потоками могла вызвать эту ошибку. Учитывая мое заявление, оно немного надуманно, но единственное, о чем я могу думать. Прежде чем я изменю код, чтобы в целом сделать его лучше, я хотел бы убедиться, что нашел причину исключения, чтобы быть уверенным, что исправил его.
Можно ли, например, войти в код .net? Я использую VS 2005 / .net 2.0, но я думаю, что в VS 2008 вы можете просмотреть источник .NET Framework? Если это так, могу ли я создать двухпоточный сценарий и повторить эту проблему? Или есть способ, который не требует от меня установки VS 2008?