Prism DI 容器 - 处理不需要的对象
Prism DI container - dispose unnecessary objects
我在处理 DI 容器中不需要的对象时遇到问题。我将 Prism 用于 Xamarin.Forms 和 Unity 容器。
应用程序从一些数据库获取配置,使用此配置创建一些服务并使用 ContainerControlledLifetimeManager 在容器中注册此服务。在解析视图和视图模型时使用此服务。
当配置更改时,应用程序再次检索更改的配置,现在问题来了:如何删除以前的注册并注册新服务?如果我只是重新注册服务,那么在处理容器之前,之前的服务不会被 GC 处理。
我无法处理容器,因为它是由 Prism 创建和管理的(我可以吗?)。
我不能使用子容器,因为 Prism 不会使用子容器解析视图和视图模型(可以吗?)
我应该使用不同的 DI 吗? Autofac 或其他 DI 是否支持这种方法?
编辑:
我刚刚测试了在 Unity 中处理重新注册的对象。结果是重新注册使用:
Container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager())
真正释放之前注册的对象。但我也有注册只使用类型:
Container.RegisterType<Foo>(new ContainerControlledLifetimeManager())
或使用实例:
Container.RegisterInstance(new Foo())
并且这些对象在重新注册时不会被释放。
那么现在唯一的解决办法就是重构Unity容器?或者试试其他ioc容器?
如果不了解您要实现的目标的所有细节,就不可能为您提供可靠的路线图,因此我将谈及一些需要考虑的事项。
重新注册服务
如果您有一些服务 IFoo
,以及两个实现 FooA
和 FooB
,并且您最初将 FooA
注册为 IFoo
的实现(使用容器控制的生命周期,在容器中注册 FooB
应该处理 FooA
实例,并且应该在以后生成 FooB
。
重建容器
如果必须重构Container,应该是可以的。我从来没有 运行 进入过我不得不尝试像你想做的那样的用例。对于初学者,您可能想看看 PrismApplicationBase
中的 Initialize
方法。这是构建和设置容器的地方。要处理重建,您需要创建一个您在应用程序中订阅的事件 class。
public partial class App
{
protected override void OnInitialized()
{
var ea = Container.Resolve<IEventAggregator>();
ea.GetEvent<SettingsChangedEvent>().Subscribe(OnSettingsChangedEvent);
// navigate
}
private void OnSettingsChangedEvent()
{
var ea = Container.Resolve<IEventAggregator>();
// prevent a memory leak
ea.GetEvent<SettingsChangedEvent>().Unsubscribe(OnSettingsChangedEvent);
// If you need platform specific types be sure to register either the
// IPlatformInitializer or some similar helper
var platformInitializer = Container.Resolve<IPlatformInitializer>();
ModuleCatalog = CreateModuleCatalog();
ConfigureModuleCatalog();
Container = CreateContainer();
ConfigureContainer();
// This would be your original RegisterTypes, so this assumes you
// look at your settings when initially registering types.
RegisterTypes();
// See notes above
platformInitializer.RegisterTypes(Container);
NavigationService = CreateNavigationService();
InitializeModules();
// Your container is now reset.
var ea = Container.Resolve<IEventAggregator>();
ea.GetEvent<SettingsChangedEvent>().Subscribe(OnSettingsChangedEvent>()
}
}
容器
至于选择容器。 Unity 没有任何问题。只要知道,当您使用 Unity 时,您将坚持使用它的方式,因为它显然现在是一个死项目。 Ninject for Prism Forms 使用了一个似乎不再维护的 PCL 变体,但是当切换到 NetStandard 时,Prism 将能够以 Ninject 的当前版本为目标。至于 Autofac,您正在处理一个不可变的容器,因此一旦您解决了某些问题,您就无法更新任何新注册。出于与 Ninject 相同的原因,Autofac for Prism Forms 也是一个落后的版本。 DryIoc for Prism forms 是一个很棒的容器,实际上是我在所有当前项目中使用的容器。它也在积极维护中,因此您可以期待您 运行 参与的用例至少会被听到。
感谢 Dan S. 和 R. Richards 的帮助。
重新创建 Prism 容器导致导航出现问题。也许可以修复它,但我不知道如何。
使用不同的 IOC 容器需要花费太多时间来学习。
我最终得到了自定义生命周期管理器(R. Richards link 中提供的解决方案):
class CustomLifetimeManager : LifetimeManager
{
private object _Value;
public override object GetValue()
{
return _Value;
}
public override void RemoveValue()
{
_Value = null;
}
public override void SetValue(object newValue)
{
_Value = newValue;
}
}
生命周期以上的经理允许删除注册:
public static class UnityContainerExtension
{
/// <summary>
/// Removes registrations that were registred using <see cref="CustomLifetimeManager"/>
/// </summary>
/// <param name="container"></param>
public static void RemoveCustomLifetimeRegistrations(this IUnityContainer container)
{
var registrations = container.Registrations.Where(r => r.LifetimeManagerType == typeof(CustomLifetimeManager));
foreach(var r in registrations)
{
r.LifetimeManager.RemoveValue();
}
}
}
我在处理 DI 容器中不需要的对象时遇到问题。我将 Prism 用于 Xamarin.Forms 和 Unity 容器。
应用程序从一些数据库获取配置,使用此配置创建一些服务并使用 ContainerControlledLifetimeManager 在容器中注册此服务。在解析视图和视图模型时使用此服务。 当配置更改时,应用程序再次检索更改的配置,现在问题来了:如何删除以前的注册并注册新服务?如果我只是重新注册服务,那么在处理容器之前,之前的服务不会被 GC 处理。
我无法处理容器,因为它是由 Prism 创建和管理的(我可以吗?)。
我不能使用子容器,因为 Prism 不会使用子容器解析视图和视图模型(可以吗?)
我应该使用不同的 DI 吗? Autofac 或其他 DI 是否支持这种方法?
编辑:
我刚刚测试了在 Unity 中处理重新注册的对象。结果是重新注册使用:
Container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager())
真正释放之前注册的对象。但我也有注册只使用类型:
Container.RegisterType<Foo>(new ContainerControlledLifetimeManager())
或使用实例:
Container.RegisterInstance(new Foo())
并且这些对象在重新注册时不会被释放。
那么现在唯一的解决办法就是重构Unity容器?或者试试其他ioc容器?
如果不了解您要实现的目标的所有细节,就不可能为您提供可靠的路线图,因此我将谈及一些需要考虑的事项。
重新注册服务
如果您有一些服务 IFoo
,以及两个实现 FooA
和 FooB
,并且您最初将 FooA
注册为 IFoo
的实现(使用容器控制的生命周期,在容器中注册 FooB
应该处理 FooA
实例,并且应该在以后生成 FooB
。
重建容器
如果必须重构Container,应该是可以的。我从来没有 运行 进入过我不得不尝试像你想做的那样的用例。对于初学者,您可能想看看 PrismApplicationBase
中的 Initialize
方法。这是构建和设置容器的地方。要处理重建,您需要创建一个您在应用程序中订阅的事件 class。
public partial class App
{
protected override void OnInitialized()
{
var ea = Container.Resolve<IEventAggregator>();
ea.GetEvent<SettingsChangedEvent>().Subscribe(OnSettingsChangedEvent);
// navigate
}
private void OnSettingsChangedEvent()
{
var ea = Container.Resolve<IEventAggregator>();
// prevent a memory leak
ea.GetEvent<SettingsChangedEvent>().Unsubscribe(OnSettingsChangedEvent);
// If you need platform specific types be sure to register either the
// IPlatformInitializer or some similar helper
var platformInitializer = Container.Resolve<IPlatformInitializer>();
ModuleCatalog = CreateModuleCatalog();
ConfigureModuleCatalog();
Container = CreateContainer();
ConfigureContainer();
// This would be your original RegisterTypes, so this assumes you
// look at your settings when initially registering types.
RegisterTypes();
// See notes above
platformInitializer.RegisterTypes(Container);
NavigationService = CreateNavigationService();
InitializeModules();
// Your container is now reset.
var ea = Container.Resolve<IEventAggregator>();
ea.GetEvent<SettingsChangedEvent>().Subscribe(OnSettingsChangedEvent>()
}
}
容器
至于选择容器。 Unity 没有任何问题。只要知道,当您使用 Unity 时,您将坚持使用它的方式,因为它显然现在是一个死项目。 Ninject for Prism Forms 使用了一个似乎不再维护的 PCL 变体,但是当切换到 NetStandard 时,Prism 将能够以 Ninject 的当前版本为目标。至于 Autofac,您正在处理一个不可变的容器,因此一旦您解决了某些问题,您就无法更新任何新注册。出于与 Ninject 相同的原因,Autofac for Prism Forms 也是一个落后的版本。 DryIoc for Prism forms 是一个很棒的容器,实际上是我在所有当前项目中使用的容器。它也在积极维护中,因此您可以期待您 运行 参与的用例至少会被听到。
感谢 Dan S. 和 R. Richards 的帮助。
重新创建 Prism 容器导致导航出现问题。也许可以修复它,但我不知道如何。
使用不同的 IOC 容器需要花费太多时间来学习。
我最终得到了自定义生命周期管理器(R. Richards link 中提供的解决方案):
class CustomLifetimeManager : LifetimeManager
{
private object _Value;
public override object GetValue()
{
return _Value;
}
public override void RemoveValue()
{
_Value = null;
}
public override void SetValue(object newValue)
{
_Value = newValue;
}
}
生命周期以上的经理允许删除注册:
public static class UnityContainerExtension
{
/// <summary>
/// Removes registrations that were registred using <see cref="CustomLifetimeManager"/>
/// </summary>
/// <param name="container"></param>
public static void RemoveCustomLifetimeRegistrations(this IUnityContainer container)
{
var registrations = container.Registrations.Where(r => r.LifetimeManagerType == typeof(CustomLifetimeManager));
foreach(var r in registrations)
{
r.LifetimeManager.RemoveValue();
}
}
}