问题 IoC - 构造函数将运行时值作为一个参数,将服务作为另一个参数


我有一个WPF应用程序,当它启动时,查看文件系统的一些配置文件

对于它找到的每个配置文件,它会在不同的窗口中显示一些信息

每个窗口都有一个关联的ViewModel对象,该对象绑定到windows datacontext

因此,为每个配置文件创建一个新的ViewModel。表示配置文件中数据的对象将传递给viewmodels构造函数

但是,View模型还有其他依赖项传递给构造函数

代码看起来像这样(在从app.xaml启动的引导程序中)

foreach (WindowConfig config in ConfigManager.GetConfigs())
{
    IMyService svc = new MyService();

    //change to resolve from IoC container
    MyViewModel vm = new MyViewModel(config, svc);

    Window1 view = new Window1();

    view.DataContext = vm;

    window.show();
}

我想使用Castle IoC contaoiner解决这些依赖关系。我知道如何为IMyService做到这一点,但我怎么能为从配置文件创建的特定类做到这一点?

谢谢


8715
2018-03-22 21:12


起源



答案:


永远记住,在应用程序代码中,从容器中提取永远不是解决方案。 应用程序代码应该不知道有一个DI容器在起作用

当您需要基于运行时值解析依赖关系时的一般解决方案是使用抽象工厂

在你的情况下,工厂可能看起来像这样(假设你的 config 变量是字符串:

public interface IViewModelFactory
{
    IViewModel Create(string configuration);
}

现在,您可以将IViewModelFactory作为单个依赖项注入循环配置文件的类中。

要实现IViewModelFactory,您可以手动执行或使用Castle Windsor 类型工厂设施 为你实现它。


8
2018-03-23 07:49



嗯...不太明白。这不仅仅是为问题添加一层抽象吗?我仍然需要将参数传递给create方法,但还需要解析一个容器。你有机会解释一下......我的工厂看起来像这样:public interface IViewModelFactory {IViewModel Create(WindowConfig configuration,IMyService svc); - ChrisCa
此外,这一切都发生在我的bootstrapping类中。这是我第一次打到容器的地方。因此,将依赖性传递给那将意味着它不会被容器解决......你可能会说,我有点困惑 - ChrisCa
我看到你几次回答这个问题 - 这是最终让我理解的解释......谢谢 stackoverflow.com/questions/1926826/cant-combine-factory-di - ChrisCa


答案:


永远记住,在应用程序代码中,从容器中提取永远不是解决方案。 应用程序代码应该不知道有一个DI容器在起作用

当您需要基于运行时值解析依赖关系时的一般解决方案是使用抽象工厂

在你的情况下,工厂可能看起来像这样(假设你的 config 变量是字符串:

public interface IViewModelFactory
{
    IViewModel Create(string configuration);
}

现在,您可以将IViewModelFactory作为单个依赖项注入循环配置文件的类中。

要实现IViewModelFactory,您可以手动执行或使用Castle Windsor 类型工厂设施 为你实现它。


8
2018-03-23 07:49



嗯...不太明白。这不仅仅是为问题添加一层抽象吗?我仍然需要将参数传递给create方法,但还需要解析一个容器。你有机会解释一下......我的工厂看起来像这样:public interface IViewModelFactory {IViewModel Create(WindowConfig configuration,IMyService svc); - ChrisCa
此外,这一切都发生在我的bootstrapping类中。这是我第一次打到容器的地方。因此,将依赖性传递给那将意味着它不会被容器解决......你可能会说,我有点困惑 - ChrisCa
我看到你几次回答这个问题 - 这是最终让我理解的解释......谢谢 stackoverflow.com/questions/1926826/cant-combine-factory-di - ChrisCa


您可以通过使用重载来将参数传递给Windsor,它应该在解析构造函数时使用 IWindsorContainer.Resolve 需要一个 IDictionary 作为参数。在这个字典中,键应该是参数名称,值应该是用作参数值的对象:

var arguments = new Dictionary<string,object> {{ "config", config }, { "service", svc } };
var viewModel = container.Resolve<MyViewModel>(arguments);

2
2018-03-22 21:39



是否可以从容器中解析IMyService的具体类型(即在Windsor XML或Fluent Interface中指定)。只需在字典中传递config参数?也许我需要改变它,所以配置是通过参数注入而不是构造函数注入传递的? (虽然我不喜欢这样做) - ChrisCa