使用 MS.DI,您在进行如下注册时很容易遇到所谓的Torn Lifestyle 问题:
// Bad idea: don't do this!
services.AddSingleton<C<X>>();
services.AddSingleton<IB<X>, C<X>>();
services.AddSingleton<IA<X>, C<X>>();
这三个注册导致C<X> 的三个单独注册,这导致三个单独的实例。这个问题被称为撕裂的生活方式。
相反,无论您是通过其IA<X> 或IB<X> 接口请求它,还是直接通过C<X> 的具体类型请求它,您都希望能够始终独立地解析C<X> 的同一个实例.
使用 MS.DI 实现此目的的方法是让两个注册将解析重定向到第三个注册。例如:
services.AddSingleton<C<X>>();
services.AddSingleton<IA<X>>(
c => c.GetRequiredService<C<X>>());
services.AddSingleton<IB<X>>(
c => c.GetRequiredService<C<X>>());
不幸的是,这种解决方案有其局限性,尤其是在使用泛型类型时。由于您的 C<T> 是一个泛型类型,您可能希望能够将 T 替换为任何合适的类型,而不必显式地为所有这些类型进行所有注册。
MS.DI 通过进行如下注册来允许这种情况:
services.AddSingleton(typeof(IA<>), typeof(C<>));
当请求IA<T> 的任意关闭版本时,此注册允许解析C<T> 的任意关闭版本。换句话说,当请求IA<Person> 时,您将获得C<Person> 的单个实例。这是自动注册的一种形式,它允许通过一次注册来解析多种类型。
但现在麻烦开始了,因为使用 MS.DI,不可能将防止 Torn Lifestyle 问题的第一种方法与后一种自动注册方法集成在一起。这是因为,对于 MS.DI,防止 Torn Lifestyle 问题的唯一方法是使用委托进行注册。但是没有 AddSingleton(Type, Func<IServiceProvider, Object>) 重载可以实现这一点,据我所知,不可能在 MS.DI 之上构建这样的功能。
这意味着在防止 Torn Lifestyles 用于开放通用注册时,MS.DI 没有合适的解决方案。我能想到两种解决方法:要么手动进行所有封闭式注册,要么将C<T> 的使用及其接口隐藏在代理或外观后面。然而,它的外观很大程度上取决于您的设计,因此不可能更具体地说明这一点。