为什么要使用ImportingConstructor

ILo*_*els 15 .net mef

我试图了解何时[ImportingConstructor]比使用[import]装饰属性更合适.这是个人偏好,还是允许其他DI容器构建类或者[import]有什么好处的东西?

我想也许如果你不想暴露公共财产,但MEF也会解决私人领域,那么又有什么好处呢?

Jar*_*Par 24

使用的问题[Import]在于它将对象的创建分为两个不同且可观察的阶段:创建和初始化.在哪里[ImportingConstructor]允许它作为单个阶段保持与每个其他.Net对象完全相同.

这种差异在许多方面都可以观察到

  1. [Import]在字段上添加新内容会更改类型的逻辑协定.但它并没有改变公共或使用合同.这意味着以前编译的任何代码都将继续编译,即使对象依赖项已更改(想想单元测试).这需要编译时错误并使其成为运行时错误.
  2. 如果您有代码合同,则代码合同无法使用[Import].合同验证引擎正确识别所有字段都可以作为null值存在,并且在每次使用字段之前都需要检查.
  3. 即使您的对象在逻辑上可以具有在初始化时设置的字段并且之后从不重置,但您无法readonly像使用普通的C#对象那样表达它.

  • 关于#3的@ILovePaperTowels,根据我的经验,大多数时候你做一个`[导入]`它对于曾经设置过的字段永远不会改变.在C#中,这通过使字段"readonly"表示,但在`[Import]`情况下不起作用,因为该字段是在构造函数完成后分配的,这违反了`readonly`.这实际上(和可怕的)将通过反射工作,但使其与非MEF组合物的使用几乎不可能 (3认同)

Mat*_*ott 9

而不是纯粹根据MEF思考,从更广泛的意义上看你的课堂设计.通常,在设计类时,您有一组关联的属性,这些属性可以是服务,例如,

public class MyService
{
  public ILogger Logger { get; set; }

  public void SaySomething()
  {
    Logger.Log("Something");
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,我可以继续创建一个实例:

var service = new MyService();
Run Code Online (Sandbox Code Playgroud)

现在,如果我尝试使用该方法:

service.SaySomething();
Run Code Online (Sandbox Code Playgroud)

如果我不明确知道我还必须初始化我的Logger财产:

var service = new MyService() { Logger = new ConsoleLogger() };
Run Code Online (Sandbox Code Playgroud)

(要么):

var service = new MyService();
service.Logger = new ConsoleLogger();
Run Code Online (Sandbox Code Playgroud)

然后错误将在运行时才会变得明显.如果我们要重新定义课程:

public class MyService
{
  private readonly ILogger _logger;

  public MyService(ILogger logger)
  {
    if (logger == null) throw new ArgumentNullException("logger");

    _logger = logger;
  }

  public void SaySomething()
  {
    _logger.Log("Something");
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您尝试创建一个实例MyService,则必须ILogger为要正确初始化的对象提供此附加服务().这有助于多种方式:

  1. 表示您的类型所需的依赖关系,这形成了必须满足的初始化合同,以确保在可用状态下创建类型.
  2. 通过确保将服务传递给您的类型,可以降低运行时错误的风险.

您可以通过使用代码约定(如@JaredPar所述)在编译时进行静态检查来更好地改进此设计.

就MEF而言,你可以使用[Import]而不是[ImportingConstructor]因为MEF会在它不能满足一个类型的所有导入时抛出异常,并且只会在initialisation([ImportingConstructor])和[Import]s 之后返回类型.

通常优选构造体注射.


Ree*_*sey 5

通过使用[ImportingConstructor],您允许一个充当导出的类导入其依赖项。这极大地简化了架构,因为您可以将具体对象的依赖关系与其实现解耦。

通常,您会[ImportingConstructor]在本身标记为 的类型上使用[Export]。当类型被组合时,构造函数参数将由 MEF 提供。