在.NET MAUI中能否注入IPreferences以解耦ViewModel与静态Preferences类?
但静态类无法通过这种方式注入: - `.AddSingleton<IPreferences, Preferences>()`不可行,因为静态类不能作为类型参数; - `.AddSingleton<IPreferences>()`不可行,因为框架未提供该服务; - 尝试使用`.AddSingleton<IPreferences>(_ => Preferences.Default)`,但调用时出现以下空引用异常: ```csharp _preferences.Get("SomeKey", DateTime.Now); // 此处报错,_preferences已定义
[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object. [mono-rt] at Microsoft.Maui.Storage.PreferencesImplementation.Get[DateTime](String key, DateTime defaultValue, String sharedName) in D:\a\_work\1\s\src\Essentials\src\Preferences\Preferences.android.cs:line 141 [mono-rt] at ... 已移除文件名 ... in ...\Shells\AppShell.xaml.cs:line 51 [mono-rt] at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state) [mono-rt] at Android.App.SyncContext.<>c__DisplayClass2_0.<Post>b__0() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.App/SyncContext.cs:line 36 [mono-rt] at Java.Lang.Thread.RunnableImplementor.Run() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:line 36 [mono-rt] at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net6.0/android-31/mcw/Java.Lang.IRunnable.cs:line 84 [mono-rt] at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V(_JniMarshal_PP_V callback, IntPtr jnienv, IntPtr klazz) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 22
请问我能否注入IPreferences,还是必须自行创建基于静态Preferences的接口?
解决方案
可以直接注入IPreferences,无需自行创建接口
你遇到的空引用问题是因为Preferences.Default是延迟初始化的,在MAUI平台基础设施完成初始化前访问会返回空实例。按以下步骤操作即可解决:
- 注册服务
在MauiProgram.cs的CreateMauiApp方法中,将IPreferences注册为单例,绑定到Preferences.Default:
builder.Services.AddSingleton<IPreferences>(Preferences.Default);
- 在ViewModel中注入使用
直接在ViewModel的构造函数中接收IPreferences实例,确保不在应用启动早期(如MauiProgram内部)调用其方法,等待MAUI初始化完成后再使用:
public class MyViewModel { private readonly IPreferences _preferences; public MyViewModel(IPreferences preferences) { _preferences = preferences; } public DateTime GetSavedDate() { return _preferences.Get("SomeKey", DateTime.Now); } }
为什么之前的注入会报错?
Preferences.Default的实例由MAUI框架在平台初始化阶段创建,若在应用启动流程的早期(比如MauiProgram中直接调用_preferences.Get),此时平台环境尚未准备好,Preferences.Default还未被初始化,就会触发空引用异常。只要在页面加载完成或ViewModel正常初始化后调用,就不会有问题。
测试支持
通过注入IPreferences,你可以在单元测试中轻松使用模拟框架(如Moq)替换实现,完全脱离平台依赖:
// 单元测试示例 var mockPrefs = new Mock<IPreferences>(); mockPrefs.Setup(p => p.Get("SomeKey", It.IsAny<DateTime>())) .Returns(new DateTime(2024, 5, 1)); var viewModel = new MyViewModel(mockPrefs.Object); // 执行测试断言
内容的提问来源于stack exchange,提问作者thinkOfaNumber
相关产品推荐
相关产品推荐

