问题
I load a list from a SQLite database when my page loads and sometimes when it loads I get NullReferenceException with the error saying Object reference not set to an instance of an object.
it breaks in this code in the SQLite class file
public TableMapping GetMapping (Type type)
{
if (_mappings == null) {
_mappings = new Dictionary<string, TableMapping> ();
}
TableMapping map;
if (!_mappings.TryGetValue (type.FullName, out map)) {
map = new TableMapping (type);
_mappings [type.FullName] = map; //null here
}
return map;
}
This is what I do when my page loads
public MainPage()
{
this.InitializeComponent();
Loaded += MainPage_Loaded;
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
createDatabase();
getBowlers();
}
private async void createDatabase()
{
SQLiteAsyncConnection conn = new SQLiteAsyncConnection(BOWLERS_DATABASE);
await conn.CreateTableAsync<Bowler>();
conn = new SQLiteAsyncConnection(GAMES_DATABASE);
await conn.CreateTableAsync<Games>();
}
private async void getBowlers()
{
SQLiteAsyncConnection conn = new SQLiteAsyncConnection(BOWLERS_DATABASE);
var query = conn.Table<Bowler>();
itemListView.DataContext = await query.ToListAsync();
}
I am new to page lifecycle but it seems that I am trying to pull from the database to early possibly?
EDIT
stacktrace
System.NullReferenceException was unhandled by user code
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=mscorlib
StackTrace:
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary`2.set_Item(TKey key, TValue value)
at SQLite.SQLiteConnection.GetMapping(Type type) in c:\Users\Jeff\Dropbox\Tournament Director Windows\Tournament Director Windows\SQLite.cs:line 231
at SQLite.TableQuery`1..ctor(SQLiteConnection conn) in c:\Users\Jeff\Dropbox\Tournament Director Windows\Tournament Director Windows\SQLite.cs:line 2129
at SQLite.SQLiteConnection.Table[T]() in c:\Users\Jeff\Dropbox\Tournament Director Windows\Tournament Director Windows\SQLite.cs:line 616
at SQLite.SQLiteAsyncConnection.Table[T]() in c:\Users\Jeff\Dropbox\Tournament Director Windows\Tournament Director Windows\SQLiteAsync.cs:line 260
at Tournament_Director_Windows.MainPage.<getBowlers>d__c.MoveNext() in c:\Users\Jeff\Dropbox\Tournament Director Windows\Tournament Director Windows\MainPage.xaml.cs:line 116
InnerException:
回答1:
Based on the exception and provided stack trace, I think that your issue is what is described here.
Note:
- The exception is thrown from the Dictionary code, not from your (user) code
- The exception is NullReferenceException, not ArgumentNullException, so it's not just the argument being null
Dictionary is not thread safe. This means that access to it should be synchronised if it's accessed by several threads.
UPDATE 1
It seems like there is a bug in SQLite async handling.
回答2:
The problem with the original code is that the GetMapping method was not thread-safe. Adding a lock, below, forces it to be thread-safe and solves the problem.
Based on the answer and comments, here is the code, change the GetMapping Method in your SQLite.cs file to this
private Object thisLock = new Object(); // add lock obj
public TableMapping GetMapping(Type type, CreateFlags createFlags = CreateFlags.None)
{
// include original code in the lock block
lock (thisLock)
{
if (_mappings == null)
{
_mappings = new Dictionary<string, TableMapping>();
}
TableMapping map;
if (!_mappings.TryGetValue(type.FullName, out map))
{
map = new TableMapping(type, createFlags);
_mappings[type.FullName] = map;
}
return map;
}
}
回答3:
Try this:
if (!_mappings.ContainsKey(type.FullName))
{
_mappings.Add(map);
}
_mappings [type.FullName] = map;
来源:https://stackoverflow.com/questions/17538275/nullreferenceexception-when-page-loads