如何通过在构造函数中传递参数来保留已注册的服务使用?

How to reserve registered service usage with passing params in constructor?

我是 OOP 和 IOC 容器的新手。我需要了解如何使用依赖注入。我的应用程序的简单结构如下。

以下代码属于缓存服务:

using Akavache;

    public class CacheService : ICacheService
    {
        protected IBlobCache Cache;

        public CacheService(IBlobCache blobCache, string applicationName)
        {
            Cache = blobCache;
            BlobCache.ApplicationName = applicationName;
        }
    }

我已经在App.cs中注册了这个服务,因为我需要使用两种不同类型的相同服务。

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterSingleton<IMockApiService, MockApiService>();
    containerRegistry.RegisterSingleton<IEssentialsService, EssentialsService>();

    containerRegistry.RegisterInstance<CacheService>(new CacheService(BlobCache.LocalMachine, "MyAppName"), "LocalMachineCache");
    containerRegistry.RegisterInstance<CacheService>(new CacheService(BlobCache.UserAccount, "MyAppName"), "UserAccountCache");
}

我的ViewModel代码如下:

public class SettingsPageViewModel : BindableBase
{
    protected ICacheService CacheService { get; private set; }

    public SettingsPageViewModel(ICacheService cacheService)
    {
        CacheService = cacheService;
    }
}

以上用法是否可行?如果可能的话,我应该如何修改我的结构?提前谢谢你。

据我所知,这种用法不可能,因为您的 IoC 容器不知道如何解析 ICacheService,因为您将实例注册为 CacheService。当 DryIoc 尝试解析 SettingsPageViewModel 时,它会遇到 ICacheService 并发现未注册的类型。至少这就是 Unity 容器的行为方式。

无论如何,即使 if 你将 "LocalMachineCache""UserAccountCache" 注册为 ICacheService 我怀疑它是否有效,因为会有没有办法知道 DryIoc 哪个应该与 SettingsPageViewModel 一起使用,因此您必须定义要解析的那个。

根据其文档,Prism 通过相应的参数名称解​​析依赖项(除非我没有误解,see here)。假设您需要在您的设置中使用本地机器缓存,您可以将其注册为 "localMachineCache"(将其重命名为遵循 SettingsPageViewModel 的构造函数中常见的 C# 编码约定)并为参数指定名称

containerRegistry.RegisterInstance<ICacheService>(new CacheService(BlobCache.LocalMachine, "MyAppName"), "localMachineCache");
containerRegistry.RegisterInstance<ICacheService>(new CacheService(BlobCache.UserAccount, "MyAppName"), "userAccountCache");
public SettingsPageViewModel(ICacheService localMachineCache)
{
    CacheService = localMachineCache;
}

相应地,如果您需要两者

public SettingsPageViewModel(ICacheService localMachineCache, ICacheService userAccountCache)
{
    MachineCacheService = localMachineCache;
    UserAccountCacheService = userAccountCache;
}

编辑

虽然它写在文档中,但命名服务似乎并不像文档所述那样工作。但是,根据 IoC 容器的选择,仍然可以通过名称注入服务。

DryIoc

使用 made 参数 IContainer.Register 您可以指定一个工厂函数来创建指定类型的实例。由于 Prism 对所使用的框架进行了 IoC 抽象,您首先必须获得 DryIoc IContainer 实例

var container = ((DryIocContainerExtension)containerRegistry).Instance;

现在您可以指定如何使用

创建 SettingsPageViewModel 的实例
container.Register(Made.Of(
    () => new SettingsPageViewModel(Arg.Of<ICacheService>("LocalMachineCache"))));

传递给Arg.Of的字符串是服务密钥,服务已经注册并告诉DryIoc要解析哪个ICacheService请注意我用了你原来的名字)。

团结

有了 unity,至少有两种方法可以实现这一点。第一种是通过UnityContainerExtension获取实例(类似DryIoc版本),使用RegisterFactory

unityContainer.RegisterFactory<SettingsPageViewModel>(
    container => new SettingsPageViewModel(container.Resolve<ICacheService>("LocalMachineCache")));

另一种选择是将 DependencyAttribute 添加到视图模型的构造函数参数中

public SettingsPageViewModel([Unity.Dependency("LocalMachineCache")] ICacheService localMachineCache)
{
    CacheService = localMachineCache;
}

这可以在注册时完成:

Adapted from the docs:

container.Register<SettingsPageViewModel>(made: Made.Of(() => new SettingsPageViewModel(Arg.Of<ICacheService>("LocalMachineCache"))));

一般来说,你要避免这种事情,因为上面的注册是相当脆弱和笨重的。另外,我只是 猜测 设置页面应该得到 LocalMachineCache,因为 DryIoc 不想猜测,你会得到一个错误。

我建议您重新审视您的架构,以明确谁决定谁获得哪种 ICacheService。如果它是配置设置的普通情况,请在配置时查找它并注册适当的服务类型(并且仅此)。如果它是由用户更改的设置,您应该有一个可用服务类型的存储库和一个注入到消费者中的提供者,可以为他们提供正确的实例。无论如何,这不是容器的工作。