C# 无服务定位器的多实例依赖注入

C# 无服务定位器的多实例依赖注入,c#,dependency-injection,multiple-instances,service-locator,C#,Dependency Injection,Multiple Instances,Service Locator,我正在编写一个WPF应用程序,使用Unity作为依赖注入的Ioc 我使用以下内容创建主窗口: container.RegisterType<IMainWindow, MainWindow>(); container.RegisterType<ISecondWindow, SecondWindow>(); container.Resolve<IMainWindow>().Show(); SecondWindow没有其他窗口,因此它只在其构造函数中定义View

我正在编写一个WPF应用程序,使用Unity作为依赖注入的Ioc

我使用以下内容创建主窗口:

container.RegisterType<IMainWindow, MainWindow>();
container.RegisterType<ISecondWindow, SecondWindow>();

container.Resolve<IMainWindow>().Show();
SecondWindow没有其他窗口,因此它只在其构造函数中定义ViewModels

public partial class MainWindow: Window, IMainWindow
{
    public MainWindow(IMainWindowViewModel viewModel, ISecondWindow secondWindow)
    {
        //with this solution I can open the second window from IMainWindowViewModel (viewmodels has no reference to windows which are in a separate project)
        viewModel.OpenSecondWindow += (s,e) => secondWindow.Show();
    }
public partial class SecondWindow: Window, ISecondWindow
{
    public SecondWindow(ISecondWindowViewModel viewModel)
然后,所有依赖项都以级联方式解析(窗口->视图模型->服务->存储库)

在我只有第二个窗口的一个实例之前,这是非常有效的,但是

如果我可以同时打开ISecondWindow的N个窗口/实例(例如,我有一个列表,双击第一行并打开一个包含第一行详细信息的ISecondWindow,然后双击第二行并打开另一个包含第二行详细信息的ISecondWindow(这样我可以同时查看第一行和第二行详细信息))?

使用DI无法实现这一点,因为我拥有并且只能使用ISecondWindow的一个实例

我想解决这个问题的唯一方法是使用服务定位器,但服务定位器是一种反模式,我不会使用它


您有什么想法/建议来解决这个问题吗?

尝试使用TransientLifetimeManager注册您的ISecondWindow


请将当前的
ISecondWindow
注册方法包括在内,但该方法不起作用。将第二个窗口插入主窗口有什么好处?像MVVM这样的IIRC框架交叉使用反射来确定哪个窗口链接到VM。DI的主要好处是测试——但是将一个窗口注入另一个窗口仍然会留下一个UI元素进行测试。很明显,SecondWindow的所有依赖项都是以级联方式注入的(ISecondWindow->ISecondWindowViewModel->ISecondWindowService->ISecondWindowRepository等)。您提到:WPF应用程序不必知道容器的存在,您对此有何反对理由?因为我认为,如果每次创建新窗口时只调用
container.Resolve()
,您将得到所需的内容,而不是将其传递到构造函数中。@Nathanwery因为容器应该只在合成根中使用,所以在合成根中使用它就像是作为服务定位器->反模式一样“如果您使用DI容器,组合根目录应该是您使用DI容器的唯一位置。在组合根目录外使用DI容器会导致服务定位器反模式“但这使我将容器用作服务定位器,我的WPF项目不必知道容器的存在。构造函数
公共主窗口中不会有任何更改(IMainWindowViewModel viewModel,ISecondWindow secondWindow)
在这种情况下,实际上您已经在使用它了,因为它是默认的:
TransientLifetimeManager是默认的生存期管理器。每次调用Resolve()或ResolveAll()方法时,它都会创建一个请求类型的新对象。
在您的情况下,这发生在构造函数中。