初始配置后在 IoC 容器中注册

发布于 2024-10-08 13:46:32 字数 1222 浏览 0 评论 0原文

我有一个场景,我想在容器中注册组件的单个实例,但不幸的是它无法在应用程序启动时创建。 该组件只能通过一些对象进行实例化,这些对象仅在应用程序生命周期稍后才可用(但是,它们不是其他 IoC 注册服务)[请参阅下面的注释]

  • 在初始配置(在应用启动时运行)之后在 IoC 容器中注册组件是一种不好的做法吗?
  • 如何在不直接引用容器的情况下完成它?我应该抽象注册服务吗?
  • 有更好的方法来支持该场景吗?

关于实际场景的注释
我想要放入容器中的组件是使用 UI 控件的特定实例(它基本上是一个适配器)进行初始化的,因此我必须手动创建组件实例并将其注册到容器中。
我本可以在应用程序启动时完成此操作,但不幸的是我还没有可用的 UI 控件实例(我也无法自己创建它)。
即使在以后,如果不知道其他组件的具体类,我也无法从它们的表面访问 UI 控件实例。
出于这个原因,我认为我可以将适配器注册的责任放入拥有 UI 控件的类中。

我最初的情况:

public interface IDockManager { ... }
public class AcmeDockManagerAdapter : IDockManager  {
    public AcmeDockManager(DockControl control) { ... }
    ...
}

public class ShellViewModel { ... }
public class ShellView : Window { 
    internal DockControl theDockControl;
} 

public class AnotherViewModel {
     AnotherViewModel(IDockManager dockManager) { ... }
}

我不满意的解决方案:

public class ShellView : Window { 
    internal DockControl theDockControl;
    public ShellView () {
        InitializeComponents();
        var dockManager = new AcmeDockManagerAdapter(theDockControl);
        //registration in the container
    }
} 

I have a scenario where I would like to register a single instance of a component in the container, but unfortunately it cannot be created at application startup.
This component could only be instantiated passing some objects which are only available a bit later in application lifecycle (they are not other IoC registered services, however) [see note below].

  • Is registering a component in a IoC container after the initial configuration (run in app startup) a bad practice?
  • How to accomplish it without directly referencing the container? Should I abstract a registration service?
  • There is a better approach to support the scenario?

NOTE about the actual scenario
The component I would like to put in the container is initialized with a particular instance of an UI control (it is basically an adapter), hence I have to manually create the component instance and register it in the container.
I would have done this at application startup, but unfortunately I don't have the UI control instance available yet (nor can I create it by myself).
Even at later time, I cannot reach the UI control instance from the surface of other components without knowing their concrete class.
For this reason I thought I could put the responsibility for the adapter registration into the class which owns the UI control.

My initial scenario:

public interface IDockManager { ... }
public class AcmeDockManagerAdapter : IDockManager  {
    public AcmeDockManager(DockControl control) { ... }
    ...
}

public class ShellViewModel { ... }
public class ShellView : Window { 
    internal DockControl theDockControl;
} 

public class AnotherViewModel {
     AnotherViewModel(IDockManager dockManager) { ... }
}

The solution I'm unconfortable with:

public class ShellView : Window { 
    internal DockControl theDockControl;
    public ShellView () {
        InitializeComponents();
        var dockManager = new AcmeDockManagerAdapter(theDockControl);
        //registration in the container
    }
} 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

苍景流年 2024-10-15 13:46:32

您可以注册一个“惰性包装器”。这样的包装器实现相同的接口,并且可以立即实例化,但会在内部推迟执行工作的实际组件的创建。看一下 ploeh 的 LazyOrderShipperLazyOrderShipper2

编辑:如果我理解正确的话,你只是想将你的视图连接到你的视图模型,MVVM 风格。我更喜欢让容器处理视图模型构建,但自己进行视图构建和视图模型连接。我的启动代码将如下所示:

var mainViewModel = container.Get<MainViewModel>();
var mainView = new MainView(mainViewModel);
Application.Run(mainView);

MainView 构造函数内,我将处理需要自己的视图模型的子控件:

   public MainView(MainViewModel viewModel)
   {
       // link "subviews" to "subviewmodels"
       this.SomeChildControl.ViewModel = viewModel.SomeChildViewModel;

       // normal MVVM property wiring
       viewModel.TitleChanged += delegate { this.Text = viewModel.Title; };
       ...
   }

如果您严格遵循 MVVM 方法,那么您不必向容器注册任何视图。任何“需要与视图对话”的东西实际上都需要与底层视图模型对话。 (当您想要在选项卡式界面或停靠窗口 GUI 中允许可插入视图时,事情会变得更有趣,但那是另一个故事了。)

You could register a "lazy wrapper" instead. Such a wrapper implements the same interface and can be instantiated immediately, but will internally postpone the creation of the actual component that does the work. Take a look at ploeh's example of a LazyOrderShipper or LazyOrderShipper2.

edit: If I understand correctly, you're just trying to connect your views to your viewmodels, MVVM-style. I prefer to let the container handle viewmodel construction, but to do the view construction and viewmodel wiring myself. My start-up code woul look like this:

var mainViewModel = container.Get<MainViewModel>();
var mainView = new MainView(mainViewModel);
Application.Run(mainView);

And inside the MainView constructor I'd take care of child controls which require their own viewmodel:

   public MainView(MainViewModel viewModel)
   {
       // link "subviews" to "subviewmodels"
       this.SomeChildControl.ViewModel = viewModel.SomeChildViewModel;

       // normal MVVM property wiring
       viewModel.TitleChanged += delegate { this.Text = viewModel.Title; };
       ...
   }

If you strictly follow the MVVM approach, then you should not have to register any view with the container. Anything that "needs to talk to the view" really needs to talk to underlying viewmodel instead. (Things get more interesting when you want to allow for pluggable views in tabbed interface or docked window GUI, but that's another story.)

最好是你 2024-10-15 13:46:32

根据我理解问题的方式,解决方案相对简单 - 从外部提供 theDockControl 。我知道这会扰乱自动生成的 WinForms/WPF/无论您使用什么垃圾,但恐怕这里没有漂亮的解决方案。

The solution the way I understand the question, is relatively simple - provide theDockControl from outside. I know that's messing with autogenerated WinForms/WPF/whatever-you're-using crap, but I'm afraid there's no pretty solutions here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文