Bev*_*van 5 c# wpf simple-injector .net-core
作为创建我的 SimpleInjector 容器的一部分,我遵循了推荐的做法并调用container.Verify()
以检查我的类型注册是否有意义。
这工作得很好,并且发现了我犯的许多错误 - 但它也会产生我想清理的碎片。
我的一个类是单例事件中心,用于在其他瞬态组件之间路由消息;这些其他组件在其构造函数中接受事件中心,创建订阅以接收他们有兴趣接收的消息,然后Dispose()
在完成时创建订阅。
调用container.Verify()
创建每种对象中的一个,导致大量这些其他瞬态实例徘徊,因为事件中心仍然知道它们的订阅。
目前,我通过Verify()
在应用程序启动之前立即手动终止所有订阅来解决这个问题。然而,这感觉像是一个必须已经解决的问题,尽管我无法在文档、Stack Overflow 上或通过搜索找到答案。
也许使用有范围的生活方式是解决方案?它们似乎不相关,因为我正在构建 WPF 应用程序,但如果我知道答案,我就不会在这里问了!
1 月 12 日更新- 根据@steven 的要求,这里有一些代码来演示我的问题。
我尝试(但失败)用既可编译又足够短的内容来内联共享的东西来演示这个问题;相反,我展示了一些实际项目的代码摘录。如果您想查看整个内容,可以在 GitHub 上找到 WordTutor 项目。
在我的应用程序的核心,我有一个单例IReduxStore<T>
,它既封装了应用程序状态,又充当了一种事件中心。其他类订阅存储以便在应用程序状态更改时主动通知。
这是IReduxStore<T>
,精简到必需品:
// IReduxStore.cs
public interface IReduxStore<T>
{
T State { get; }
void Dispatch(IReduxMessage message);
IDisposable SubscribeToReference<V>(
Func<T, V?> referenceReader,
Action<V?> whenChanged)
where V : class, IEquatable<V>?;
}
Run Code Online (Sandbox Code Playgroud)
订阅落实IDisposable
作为确定性清理方便和习惯的方法时,不再需要预订。
商店注册为单例,绑定到特定类型的状态:
// Program.cs
container.RegisterSingleton<
IReduxStore<WordTutorApplication>,
ReduxStore<WordTutorApplication>>();
Run Code Online (Sandbox Code Playgroud)
实施IReduxStore<T>
存储所有订阅:
private readonly HashSet<ReduxSubscription<T>> _subscriptions
= new HashSet<ReduxSubscription<T>>();
Run Code Online (Sandbox Code Playgroud)
它们从HashSet
处置时移除。
我的许多 ViewModel 接受IReduxStore<WordTutorApplication>
它们的构造函数,以便它们可以订阅更新:
// VocabularyBrowserViewModel.cs
public sealed class VocabularyBrowserViewModel : ViewModelBase
{
private readonly IReduxStore<WordTutorApplication> _store;
private readonly IDisposable _screenSubscription;
private readonly IDisposable _vocabularySubscription;
public VocabularyBrowserViewModel(IReduxStore<WordTutorApplication> store)
{
_store = store ?? throw new ArgumentNullException(nameof(store));
// ... elided ...
_screenSubscription = _store.SubscribeToReference(
app => app.CurrentScreen as VocabularyBrowserScreen,
RefreshFromScreen);
_vocabularySubscription = _store.SubscribeToReference(
app => app.VocabularySet,
RefreshFromVocabularySet);
// ... elided ...
}
// ... elided ...
}
Run Code Online (Sandbox Code Playgroud)
ViewModels 注册为瞬态,因为每个窗口都需要一个唯一的实例:
// Program.cs
var desktopAssembly = typeof(WordTutorWindow).Assembly;
container.Collection.Register<ViewModelBase>(desktopAssembly);
Run Code Online (Sandbox Code Playgroud)
当不再需要它们时,ViewModel 会主动释放它们的订阅:
// VocabularyBrowserViewModel.cs
private void RefreshFromScreen(VocabularyBrowserScreen? screen)
{
if (screen == null)
{
_screenSubscription.Dispose();
_vocabularySubscription.Dispose();
return;
}
Selection = screen.Selection;
Modified = screen.Modified;
}
Run Code Online (Sandbox Code Playgroud)
当Verify()
在 SimpleInjector 容器上调用时,会创建每个对象的示例,包括单例IReduxStore<T>
。瞬态的ViewModels(如VocabularyBrowserViewModel
上面所示)也被创建,但这些情况下保持住,因为他们的订阅仍然由店举办。
我尝试IDisposable
在 ViewModels 上实现,但因为他们的生活方式是瞬态的,唯一的影响是在Verify()
被调用时生成一个额外的警告。
更新 II,1 月 12 日:
我目前的解决方法是在容器成功初始化后,作为应用程序启动的一部分手动清除所有订阅:
var store = (ReduxStore<WordTutorApplication>)
container.GetInstance<IReduxStore<WordTutorApplication>>();
store.ClearSubscriptions();
Run Code Online (Sandbox Code Playgroud)
这感觉就像一个讨厌的黑客。首先它需要显式转换为实现类型,然后它调用一个根本不需要存在的方法。
尝试EnableAutoVerification
在 Simple Injector 5.0 ( https://simpleinjector.org/ReferenceLibrary/html/P_SimpleInjector_ContainerOptions_EnableAutoVerification.htm )中设置为 false
归档时间: |
|
查看次数: |
289 次 |
最近记录: |