我可以将 Microsoft.Maui.Storage.Preferences 抽象为 MAUI 中的 IPreferences

thi*_*ber 3 .net dependency-injection maui

我正在编写一个 .NET MAUI 应用程序,我想在我的 ViewModel 中使用Microsoft.Maui.Storage.Preferences,但是不希望将我的 ViewModel 绑定到静态Preferences类,否则将很难测试。所以我注意到有一个IPreferences接口,但我不知道它的目的是什么,因为我无法注入静态实现(并且首选项是静态的)。

在我的启动课程中,我做了通常的builder.Services.AddSingleton()事情.AddTransient()

builder.Services
        .AddSingleton<AppShell>()
        .AddTransient<MyViewModel>()
        ...
Run Code Online (Sandbox Code Playgroud)

但我不能用静态类来做到这一点。这是行不通的,因为你不能使用静态类作为类型参数:

        .AddSingleton<IPreferences, Preferences>()
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为框架不提供它:

        .AddSingleton<IPreferences>()
Run Code Online (Sandbox Code Playgroud)

我试着变得更奇特:

        .AddSingleton<IPreferences>(_ => Preferences.Default)
Run Code Online (Sandbox Code Playgroud)

但我在使用它时收到此错误:

    _preferences.Get("SomeKey", DateTime.Now); // error here, but _preferences is defined
Run Code Online (Sandbox Code Playgroud)

[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 ... my filenames removed ... 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

Run Code Online (Sandbox Code Playgroud)

我可以注入 IPreferences 还是必须创建由静态首选项支持的自己的接口?

H.A*_*.H. 7

IPreferences 用于保存小型键值对。您可以引用 Preferences.Default 来注入它。

然后使用:

settings.Get("Language", 0);
Run Code Online (Sandbox Code Playgroud)

其中设置是:

IPreferences settings;
Run Code Online (Sandbox Code Playgroud)

我喜欢做的是制作 SettingsService,然后使用:

public int Language
{
    get => settings.Get("Language", 0);
    set => settings.Set("Language", value);
}
Run Code Online (Sandbox Code Playgroud)

还有其他方法可以处理您的设置,但对于很少的值,这对我有用。

编辑(您请求的代码。)

注射:

builder.Services.AddSingleton<ISettings>(new SettingsService(Preferences.Default));
Run Code Online (Sandbox Code Playgroud)

I设置界面:

public interface ISettings
{
    int Language { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

设置服务类:

internal class SettingsService : ISettings
{
    IPreferences settings;

    public SettingsService(IPreferences settings)
    {
        this.settings = settings;
    }

    public int Language
    {
        get => settings.Get("Language", 0);
        set => settings.Set("Language", value);
    }
}
Run Code Online (Sandbox Code Playgroud)

在 ViewModel 中使用:

public MyViewModel(ISettings settings)
{
    lang = settings.Language;
}
Run Code Online (Sandbox Code Playgroud)

Edit2:因为你不想“手动构建”。你可以这样做。

builder.Services.AddSingleton<IPreferences>(Preferences.Default);
builder.Services.AddSingleton<ISettings, SettingsService>();
Run Code Online (Sandbox Code Playgroud)

这样您就可以使用 IPreferences 以及 ISettings。SettingsService 构造函数将使用此处注入的 IPreferences。