【问题标题】:How to combine designable components with dependency injection如何将可设计组件与依赖注入相结合
【发布时间】:2010-11-06 23:56:24
【问题描述】:

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

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

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

  • 服务定位器

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

  • 通过属性进行依赖注入

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

  • 使用 Initialize 方法注入依赖项

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

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


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


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

【问题讨论】:

    标签: .net dependency-injection components service-locator


    【解决方案1】:

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

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

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

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

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

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

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

    【讨论】:

    • 如果我正确地解释了您的答案,您的意思是控件不应使用任何服务。我不确定我是否同意。例如,我有一个不通过调用 System.Windows.Forms.TextRenderer 直接呈现文本的控件。相反,它使用可注入的 ITextRenderer 服务(使用基本相同的方法)。这使我能够实现超出 .NET 框架提供的精美缩写策略,同时保持此类代码独立于控件本身。
    • 是的,我是说控件不应该使用任何服务——服务应该使用控件。控件除了渲染 UI 什么都不做。你可以注入花哨的缩写策略很好,但是这样的逻辑属于(视图)模型,而不是视图本身。然后,您可以通过调用注入的依赖项将您的视图数据绑定到模型上产生所需值的属性。即使您似乎在使用 WinForms,请查看以下内容以获得灵感:msdn.microsoft.com/en-us/magazine/dd419663.aspx
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-16
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 2017-05-10
    • 2017-12-14
    相关资源
    最近更新 更多