【问题标题】:NullReferenceException when page Loads页面加载时出现 NullReferenceException
【发布时间】:2013-07-06 11:20:10
【问题描述】:

当我的页面加载时,我从SQLite 数据库加载一个列表,有时当它加载时我得到NullReferenceException,错误提示为Object reference not set to an instance of an object.

它在 SQLite 类文件中中断了这段代码

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;
}

这就是我在页面加载时所做的事情

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();
}

我是页面生命周期的新手,但似乎我正试图从数据库中提早提取?

编辑

堆栈跟踪

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: 

【问题讨论】:

  • 你在哪一行得到 NullReferenceException?
  • 我在代码_mappings [type.FullName] = map;中注释了
  • _mappings 一个静态变量和/或被多个线程调用?
  • @ScottChamberlain 我从 NuGet 扩展下载的 SQLite 库中的所有内容
  • @ScottChamberlain 它是一个类范围的变量,但不是静态的private Dictionary&lt;string, TableMapping&gt; _mappings = null;

标签: c# nullreferenceexception


【解决方案1】:

试试这个:

if (!_mappings.ContainsKey(type.FullName))
{
    _mappings.Add(map);
}

_mappings [type.FullName] = map;

【讨论】:

    【解决方案2】:

    根据异常和提供的堆栈跟踪,我认为您的问题是 here 所描述的。

    注意:

    1. 异常是从字典代码中引发的,而不是从您的(用户)代码中引发的
    2. 异常是 NullReferenceException,而不是 ArgumentNullException,所以不仅仅是参数为 null

    Dictionary 不是线程安全的。这意味着如果它被多个线程访问,则对它的访问应该是同步的。

    更新 1

    在 SQLite 异步处理中看起来像 there is a bug

    【讨论】:

    • 这个调用在外部库中,所以需要同步调用到SQLite库。
    • 我希望我能给你两次 +1,我敢打赌你明白了。对SQLiteAsyncConnection 的调用不应在线程之间共享。确保Connection Pooling 已启用,它会为您重用资源而不共享连接对象。
    • 是的,这是一个线程问题,我在GetMapping 中放了一个lock,此后一直没有崩溃
    【解决方案3】:

    原始代码的问题在于 GetMapping 方法不是线程安全的。在下面添加一个锁,强制它是线程安全的并解决了问题。

    根据答案和cmets,这里是代码,把你SQLite.cs文件中的GetMapping方法改成这个

    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;
        }
    }
    

    【讨论】:

    • 请说出发生了什么变化。
    • @JohnSaunders 更新
    • @JohnSaunders 它基于此问题的已接受答案,但未提供代码。于是搜了下怎么实现锁,自己试了好几天,至今无一例外。我认为将代码贡献给这个问题会很好,所以 .net 开发的新手不需要再次搜索。我认为原因很明显。
    • 太棒了。现在在你的答案中说,基于答案和 cmets,问题在于代码不是线程安全的,添加锁使其成为线程安全的。
    • @JohnSaunders 那么应该做些什么来解决这个问题呢?为什么在没有任何建议的情况下投反对票? tyczj 在接受的答案中的评论建议了锁定解决方案。那么帮助我的锁解决方案的代码实现对其他人没有任何帮助?
    猜你喜欢
    • 2012-02-23
    • 2011-09-19
    • 2014-06-22
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    • 2019-05-13
    相关资源
    最近更新 更多