.NET MAUI项目从SQLite取数据触发NullReferenceException
.NET MAUI SQLite空引用异常排查与修复
你遇到的System.NullReferenceException出现在QuizViewModel.GetQuestionsAsync()调用_dBService.GetQuestionsAsync()时,核心原因大概率是嵌入式数据库资源加载失败,或者数据库初始化逻辑存在异步未等待的问题。以下是具体排查步骤和修复方案:
1. 检查嵌入式数据库的资源配置
这是最常见的问题根源:
- 右键项目Data文件夹下的
cbt.db文件 → 「属性」,将「生成操作」设置为嵌入的资源。如果没设置,程序无法从程序集里读取到这个文件。 - 验证资源名称是否正确:
GetManifestResourceStream的参数必须是完整的资源路径,格式为「项目命名空间.文件夹名.文件名」。比如你的项目命名空间是CBT,文件在Data文件夹,参数应为"CBT.Data.cbt.db"。如果不确定实际名称,可以在LoadDB方法里添加代码打印所有资源名:
运行后查看输出,找到var assembly = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly; Debug.WriteLine("所有嵌入式资源:" + string.Join(", ", assembly.GetManifestResourceNames()));cbt.db对应的正确名称,替换掉原代码里的参数。
2. 修复LoadDB方法的空值防护
原代码中如果资源加载失败,stream会为null,直接调用stream.CopyTo就会触发空引用。修改LoadDB:
public void LoadDB() { if (!File.Exists(DBPath)) { var assembly = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly; using Stream? stream = assembly.GetManifestResourceStream("CBT.Data.cbt.db"); if (stream == null) { Debug.WriteLine("错误:无法找到嵌入式数据库资源,请检查资源名称和生成操作设置"); return; } using MemoryStream? memoryStream = new(); stream.CopyTo(memoryStream); File.WriteAllBytes(DBPath, memoryStream.ToArray()); Debug.WriteLine("数据库文件已成功复制到本地"); } }
3. 修正数据库初始化的异步逻辑
DBService构造函数里的_database.CreateTableAsync<Question>()是异步操作,但没有await,这会导致表还没创建完成就执行查询。由于构造函数不能标记为async,我们可以把表创建逻辑移到GetQuestionsAsync里:
public async Task<List<Question>> GetQuestionsAsync() { // 确保表存在后再查询 await _database.CreateTableAsync<Question>(); return await _database.Table<Question>().ToListAsync(); }
4. 规避集合索引越界风险
QuizViewModel.CreateAsync里直接访问viewModel.Questions[viewModel._currentQuestionIndex],如果查询回来的问题集合为空或者数量不足,会触发新的异常。添加判断逻辑:
[RelayCommand] public static async Task<QuizViewModel> CreateAsync(IDBService dBService) { var viewModel = new QuizViewModel(dBService); await viewModel.GetQuestionsAsync(); // 安全设置当前问题 if (viewModel.Questions.Count > 0) { var targetIndex = viewModel._currentQuestionIndex >= viewModel.Questions.Count ? 0 : viewModel._currentQuestionIndex; viewModel.CurrentQuestion = viewModel.Questions[targetIndex]; } else { Debug.WriteLine("警告:未获取到任何问题数据"); viewModel.CurrentQuestion = null; } return viewModel; }
最后验证
做完以上修改后,运行程序,查看输出日志:
- 如果数据库资源加载成功,会打印「数据库文件已成功复制到本地」;
- 如果资源找不到,会打印对应的错误提示,再根据日志调整资源名称或生成操作设置。
内容的提问来源于stack exchange,提问作者Maxwell Kwashie
相关产品推荐
相关产品推荐

