You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在.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平台基础设施完成初始化前访问会返回空实例。按以下步骤操作即可解决:

  1. 注册服务
    在MauiProgram.cs的CreateMauiApp方法中,将IPreferences注册为单例,绑定到Preferences.Default:
builder.Services.AddSingleton<IPreferences>(Preferences.Default);
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 08:01:27