Prism/Unity使用新的具体类更新解析/注入的引用

本文关键字:更新 注入 引用 Unity Prism | 更新日期: 2023-09-27 18:27:27

我试图在运行时为启动期间注册的类型更改具体类型。我能够更新容器&服务定位器。但现有的视图模型仍然引用了引导的原始服务。

引导程序代码:

container.RegisterInstance<IMyService>(new MyServiceA(), new ContainerControlledLifetimeManager());

ViewModelCode:

public ViewModel(IMyService service)
{
    _service = service;
}

服务更改代码:

container.RegisterInstance<IMyService>(new MyServiceB(), new ContainerControlledLifetimeManager());

serviceLocator.Reve返回MyServiceB。容器中不再存在MyServiceA。但是现有的视图模型仍然引用了MyServiceA。

是否有任何方法可以更新容器更新现有/已解析的引用?

更新:也许这个单元测试可以帮助理解我所反对的行为。

    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Microsoft.Practices.Unity;
    namespace UnitTestProject1
    {
        [TestClass]
        public class UnitTest1
        {      
            [TestMethod]
            public void TestUnity()
            {
                // register ServiceA and ViewModel
                var container = new UnityContainer();
                container.RegisterType<IMyService, MyServiceA>();
                container.RegisterType<MyViewModel>();
                // resolve viewmodel
                var viewModel = container.Resolve<MyViewModel>();
                // replace ServiceA with ServiceB
                container.RegisterInstance<IMyService>(new MyServiceB());
                // Assert success, IMyService is MyServiceB
                Assert.AreEqual(container.Resolve<IMyService>().GetType(), typeof(MyServiceB));
                // Assert fails viewmodel still using MyServiceA
                Assert.AreEqual(viewModel.RegisteredService.GetType(), typeof(MyServiceB));
            }
        }    
        public interface IMyService
        {        
        }
        public class MyServiceA : IMyService
        {
        }
        public class MyServiceB : IMyService
        {
        }
        public class MyViewModel
        {
            public IMyService RegisteredService { get; }
            public MyViewModel(IMyService myService)
            {
                RegisteredService = myService;
            }

        }
    }

Prism/Unity使用新的具体类更新解析/注入的引用

如果您要为IMyService实现Proxy类,它将在每次调用时从ServiceLocator检索实际实现,那么问题就会得到解决:

public class MyServiceProxy : IMyService
{
    public int DoWork(string someParameter)
    {
        return ServiceLocator.Resolve<IMyService>().DoWork(someParameter);
    }
}

现在,您可以将MyServiceProxy注入到类构造函数中。另一种方法是向每个IMyService使用添加ServiceLocator的显式调用。但您应该记住,ServiceLocator会使您的代码更难理解,因为它隐藏了类依赖关系。

更新

绑定到检索到的数据的情况会提醒对事件的反应。当事件"数据源已更改"在您的系统中引发时,订阅者(ViewModels)将处理此事件。这是EventAggregator类的工作,它在Prism中实现了。

然后基于两部分的解决方案:

  1. 将使用IMyService的ViewModels订阅到MyServiceChangedEvent(首先应该实现它)。在处理程序中,您可以通过ServiceLocator或通过事件参数更改实现,为更新数据绑定引发PropertyChanged,并为您的案例执行其他操作。

    public class MyServiceChangedEvent : CompositeWpfEvent<IMyService>
    {
    }
    
  2. 在IMyService上发布新的MyServiceChangedEvent已更改。您可以在事件中创建新属性,以将新实现传递给订阅服务器,而不是使用ServiceLocator。

    var newMyService = new MyServiceB();
    container.RegisterInstance<IMyService>(newMyService, new ContainerControlledLifetimeManager());
    eventAggregator.GetEvent<MyServiceChangedEvent>().Publish(newMyService);
    

为什么不直接使用命名实例?

_container.RegisterType<IMyService, MyService>("ServiceA", new ContainerControlledLifetimeManager());
_container.RegisterType<IMyService, MyOtherService>("ServiceB", new ContainerControlledLifetimeManager());
_container.Resolve<IMyService>("ServiceA");