如何将可设计组件与依赖注入相结合 [英] How to combine designable components with dependency injection

查看:23
本文介绍了如何将可设计组件与依赖注入相结合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

创建可设计的 .NET 组件时,您需要提供默认构造函数.来自 IComponent 文档:

When creating a designable .NET component, you are required to provide a default constructor. From the IComponent documentation:

要成为组件,类必须实现 IComponent 接口和提供一个基本的构造函数不需要参数或单个IContainer 类型的参数.

To be a component, a class must implement the IComponent interface and provide a basic constructor that requires no parameters or a single parameter of type IContainer.

这使得通过构造函数参数进行依赖注入成为不可能.(可以提供额外的构造函数,但设计者会忽略它们.)我们正在考虑的一些替代方案:

This makes it impossible to do dependency injection via constructor arguments. (Extra constructors could be provided, but the designer would ignore them.) Some alternatives we're considering:

  • 服务定位器

不要使用依赖注入,而是使用服务定位器模式来获取依赖.这似乎是 IComponent.Site.GetService 是为了.我想我们可以创建一个可重用的 ISite 实现(ConfigurableServiceLocator?),它可以配置必要的依赖项.但这在设计师环境中如何运作?

Don't use dependency injection, instead use the service locator pattern to acquire dependencies. This seems to be what IComponent.Site.GetService is for. I guess we could create a reusable ISite implementation (ConfigurableServiceLocator?) which can be configured with the necessary dependencies. But how does this work in a designer context?

通过属性进行依赖注入

通过属性注入依赖.提供默认实例(如果是)有必要在一个组件中显示设计师.记录哪些属性需要注射.

Inject dependencies via properties. Provide default instances if they are necessary to show the component in a designer. Document which properties need to be injected.

使用 Initialize 方法注入依赖项

这很像通过属性注入,但它将需要注入的依赖项列表保存在一个地方.这样,所需依赖项的列表就会被隐式记录下来,当列表发生变化时,编译器会帮助您解决错误.

This is much like injection via properties but it keeps the list of dependencies that need to be injected in one place. This way the list of required dependencies is documented implicitly, and the compiler will assists you with errors when the list changes.

知道这里的最佳做法是什么吗?你是怎么做到的?

Any idea what the best practice is here? How do you do it?

<小时>编辑:我已经删除了(例如 WinForms UserControl)",因为我打算将问题与一般组件有关.组件都是关于控制反转的(参见 UMLv2 的第 8.3.1 节规范)所以我不认为你不应该注入任何服务"是一个很好的答案.


edit: I have removed "(e.g. a WinForms UserControl)" since I intended the question to be about components in general. Components are all about inversion of control (see section 8.3.1 of the UMLv2 specification) so I don't think that "you shouldn't inject any services" is a good answer.

<小时>edit 2:花了一些时间使用 WPF 和 MVVM 模式,最终得到"了 Mark 的答案.我现在看到视觉控制确实是一个特例.至于在设计器表面上使用非可视组件,我认为 .NET 组件模型从根本上与依赖注入不兼容.它似乎是围绕服务定位器模式设计的.也许这将随着在 System.ComponentModel.Composition 命名空间.


edit 2: It took some playing with WPF and the MVVM pattern to finally "get" Mark's answer. I see now that visual controls are indeed a special case. As for using non-visual components on designer surfaces, I think the .NET component model is fundamentally incompatible with dependency injection. It appears to be designed around the service locator pattern instead. Maybe this will start to change with the infrastructure that was added in .NET 4.0 in the System.ComponentModel.Composition namespace.

推荐答案

同样的问题困扰了我很长时间,直到我意识到我想错了.AFAIR,创建 IComponent 实现的唯一原因是提供设计时功能 - IComponent 实现没有运行时效果.

This same question bugged me for a long time until I realized that I was thinking about it in a wrong way. AFAIR, the only reason for creaing an IComponent implementation is to provide design-time features - there's no run-time effect of IComponent implementations.

因此,这意味着您应该主要创建组件来实现设计时功能.特别是对于控件,这意味着您可以配置组件以某种方式运行.意识到这与组件的实际行为方式或它显示的数据完全不同,这一点非常重要.它不应该在设计时有行为,也不应该包含数据.

By corrolary, this means that you should mostly create components to implement design-time features. Particularly for Controls, this means that you can configure the component to behave in a certain way. It is very important to realize that this is a completely different concern than how the component actually behaves or which data it displays. It should not have behavior at design-time, and nor should it contain data.

因此,对构造函数的约束实际上是一种祝福,因为它指导您重新思考您的设计.控件是一种与数据源无关的软件,它以某种方式显示数据并与数据交互.只要该数据符合某些接口等,Control 就会很高兴.如何数据到达与控件无关,也不应该是.让 Control 控制数据的加载和修改方式是错误的.

As such, the constraint on the constructor is actually a blessing, since it instructs you to rethink your design. A Control is a data-source agnostic piece of software than displays and interacts with data in a certain way. As long as that data conforms to certain interfaces, etc. the Control is happy. How that data arrives is of no concern to the Control, and neither should it be. It would be an error to let the Control control how data is loaded and modified.

在 WPF 中,这比在 Windows 窗体中明确得多:您为特定控件提供 DataContext 并将控件的属性绑定到该 DataContext 的成员.DataContext(可以是任何对象)源自 Control 外部;那是你的责任或你的表现层.

In WPF, this is explicitly much clearer than in Windows Forms: You give a particular Control a DataContext and bind properties of the Control to members of that DataContext. The DataContext (which can be any object) originates from outside the Control; that's the responsibility or your Presentation Layer.

在 Windows 窗体中,您仍然可以通过将数据上下文分配给控件来执行相同的操作.本质上,这是属性注入 - 请注意您不应该注入服务;你应该注入数据.

In Windows Forms, you can still do the same by assigning a data context to a Control. Essentially, this is Property Injection - just be aware that you should not inject services; you should inject data.

总之,我不会接受你的任何建议.相反,让控件具有一个或多个属性,允许您将数据分配给控件,并使用数据绑定来绑定此数据.在控件的实现中,准备好处理没有数据的情况:每次控件在设计时由 VS 托管时都会发生这种情况.Null Object 模式对于实现这种弹性非常有用.

In summary, I would go with neither of your suggestions. Instead, let the Control have one or more properties that allow you to assign data to the Control, and use databinding to bind against this data. Inside the Control's implementation, be prepared to handle the situation where there's no data: This will occur every time the Control is hosted by VS at design-time. The Null Object pattern very useful for implementing such resilience.

然后,从控制器设置数据上下文.这就是 MVC 的做法:Control 是 View,但您应该有一个单独的 Controller,可以实例化 Model 并将其分配给 View.

Then, set up the data context from your Controllers. That's the MVC way of doing it: The Control is the View, but you should have a separate Controller that can instantiate and assign a Model to the View.

这篇关于如何将可设计组件与依赖注入相结合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆