如何将可设计组件与依赖注入相结合

Wim*_*nen 9 .net components dependency-injection service-locator

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

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

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

  • 服务定位器

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

  • 通过属性进行依赖注入

    通过属性注入依赖项.如果需要在设计器中显示组件,请提供默认实例.记录需要注入哪些属性.

  • 使用Initialize方法注入依赖项

    这很像注入属性,但它保留了需要在一个地方注入的依赖项列表.这样,隐式记录了所需依赖项列表,编译器将在列表更改时帮助您解决错误.

知道最好的做法是什么吗?你怎么做呢?


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


编辑2:花了一些玩WPF和MVVM模式最终"得到"马克的答案.我现在看到视觉控制确实是一个特例.至于在设计器表面上使用非可视组件,我认为.NET组件模型从根本上与依赖注入不兼容.它似乎是围绕服务定位器模式设计的.也许这将随着System.ComponentModel.Composition命名空间中.NET 4.0中添加的基础结构而改变.

Mar*_*ann 6

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

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

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

在WPF中,这明显比Windows窗体更清晰:您为特定的Control提供了一个DataContext,并将Control的属性绑定到该DataContext的成员.DataContext(可以是任何对象)源自Control外部; 这是责任还是你的表达层.

在Windows窗体中,您仍然可以通过为Control分配数据上下文来执行相同操作.基本上,这是属性注入 - 只要知道你不应该注入服务; 你应该注入数据.

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

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