16

我试图了解什么时候[ImportingConstructor]比用[import]. 是个人喜好,还是允许由其他 DI 容器构建类的东西,或者有什么好处[import]

我认为,如果您不想公开公共属性,但 MEF 也会解析私有字段,那么再次,好处在哪里?

4

4 回答 4

25

using 的问题[Import]在于它将对象的创建分为两个不同且可观察的阶段:创建和初始化。Where[ImportingConstructor]允许它像其他所有 .Net 对象一样保持为单个阶段。

这种差异可以通过多种方式观察到

  1. 在字段上添加新[Import]的会更改类型的逻辑契约。然而,它不会改变公共或使用合同。这意味着即使对象依赖项发生了变化(想想单元测试),之前编译的任何代码都将继续编译。这需要编译时错误并使其成为运行时错误。
  2. 如果您有[Import]. 合同验证引擎正确识别所有字段都可以作为null值存在,并且在每次使用字段之前都需要进行检查。
  3. 即使您的对象在逻辑上可以具有在初始化时设置并且之后永远不会重置的字段,您也不能readonly像使用普通 C# 对象那样表达这一点。
于 2012-05-31T20:17:15.160 回答
11

与其单纯从 MEF 的角度思考,不如从更广泛的意义上来看待你的课程设计。通常,当您设计一个类时,您有一组关联的属性,这些可能是服务,例如,

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

  public void SaySomething()
  {
    Logger.Log("Something");
  }
}

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

var service = new MyService();

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

service.SaySomething();

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

var service = new MyService() { Logger = new ConsoleLogger() };

(或者):

var service = new MyService();
service.Logger = new ConsoleLogger();

然后错误直到运行时才会变得明显。如果我们要重新定义类:

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");
  }
}

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

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

您可以通过使用代码合同(如@JaredPar 所述)在编译时进行静态检查来进一步改进此设计。

就 MEF 而言,您可以使用 using[Import]而不是,[ImportingConstructor]因为当 MEF 不能满足类型的所有导入时,它会抛出异常,并且只会在初始化 ( [ImportingConstructor]) 和[Import]s 之后返回类型。

构造函数注入通常是可取的。

于 2012-06-01T11:04:49.783 回答
5

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

通常,您会使用[ImportingConstructor]本身标记为[Export]. 组合类型后,MEF 将提供构造函数参数。

于 2012-05-31T20:17:30.983 回答
0

构造函数参数也不支持重组。

于 2013-11-07T23:10:07.367 回答