我试图了解何时[ImportingConstructor]比使用[import]装饰属性更合适。这是个人偏好,还是允许其他DI容器构建类的东西,或者[import]有什么好处?
我认为,如果您不想公开公共财产,但MEF也会解析私有字段,那么这又有什么好处呢?
答案 0 :(得分:24)
使用[Import]
的问题在于它将对象的创建分为两个不同且可观察的阶段:创建和初始化。其中[ImportingConstructor]
允许将其保持为与其他所有.Net对象完全相同的单个阶段。
这种差异在很多方面都可以观察到
[Import]
会更改类型的逻辑合约。但它并没有改变公共或使用合同。这意味着以前编译的任何代码都将继续编译,即使对象依赖项已更改(想想单元测试)。这需要编译时错误并使其成为运行时错误。[Import]
,则代码合约将无法使用。合同验证引擎正确识别所有字段都可以作为null
值存在,并且在每次使用字段之前都需要进行检查。 readonly
来表达。答案 1 :(得分:9)
不要纯粹根据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
)。这有助于多种方式:
您可以使用代码约定(如@JaredPar所述)在编译时进行静态检查,从而进一步改进此设计。
就MEF而言,您可以使用[Import]
代替[ImportingConstructor]
,因为当MEF无法满足某个类型的所有导入时,它将抛出异常,并且只会在两者之后返回该类型初始化([ImportingConstructor]
)然后[Import]
s。
通常建议使用构造函数注入。
答案 2 :(得分:3)
通过使用[ImportingConstructor]
,您允许一个用作导出的类来导入其依赖项。这大大简化了体系结构,因为您可以将具体对象的依赖性与其实现分离。
通常情况下,您会在类型上使用[ImportingConstructor]
,该类型本身标记为[Export]
。组成类型时,构造函数参数将由MEF提供。
答案 3 :(得分:0)
构造函数参数也不支持重构。