SatisyImportsOnce
将组合一个类型而不注册它以进行重组。因此,如果您打算使用不支持重组的类型,您可以使用SatisfyImportsOnce
它将像往常一样完成工作,但是容器中的任何更改(添加新部件或删除部件),那么您的实例将不会自动重新组合以提供这些新部件。
在您的实例中,您正在使用:
[ImportMany(typeof(ICustomRenderer), AllowRecomposition = true)]
...但是通过SatisfyImportsOnce
,此导入不会被重组。
如果您不担心重组,您可以使用构造函数注入更改代码,因此您可以这样做:
[ImportingConstructor]
public FormPartCustomatorFactory(IEnumerable<Lazy<ICustomRenderer, ICustomRendererMetadata>> renderers)
{
if (renderers == null)
throw new ArgumentNullException("renderers");
_renderers = renderers.ToDictionary(r => r.Metadata.Name, r => r);
}
我建议构造函数注入的原因是,Lazy<ICustomRenderer, ICustomRendererMetadata>
实例是您的类型所需的显式依赖项,因此最好在可用状态下实例化您的类型,而不是实例化然后需要额外的步骤来准备首次使用。
这使您的FormPartCustomatorFactory
类型更容易测试。为此,如果您要这样更改构造函数,那么将其设置为单例的方法将不起作用。相反,您可以利用 MEF 的生命周期管理功能,因此可以将您的类型重新设计为:
public interface IFormPartCustomatorFactory
{
ICustomRenderer Find(string name);
}
[Export(typeof(IFormPartCustomerFactory)), PartCreationPolicy(CreationPolicy.Shared)]
public class FormPartCustomatorFactory : IFormPartCustomatorFactory
{
private IEnumerable<Lazy<ICustomRenderer, ICustomRendereMetadata>> _renderers;
[ImportingConstructor]
public FormPartCustomatorFactory(IEnumerable<Lazy<ICustomRenderer, ICustomRendererMetadata>> renderers)
{
if (renderers == null)
throw new ArgumentNullException("renderers");
_renderers = renderers;
}
public ICustomRenderer Find(string name)
{
return _renderers
.Where(r => r.Metadata.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)
.Select(r => r.Value)
.FirstOrDefault();
}
}
这样做意味着您的类型不依赖于 MEF,它可以在没有 MEF 的情况下使用,它更易于测试,并且CompositionContainer
将管理零件的使用寿命,在本例中CreationPolicy.Shared
(这是导出类型的默认设置),使用单例生命周期策略。然后您可以导入一个实例IFormPartCustomator
,您导入相同的单例实例。
我还认为称其为Factory
可能是错误的,因为工厂旨在创建新实例,而您的类型只会创建每个实例的一个实例ICustomRenderer
。如果这是预期的行为,也许最好将其称为FormPartCustomatorService
,它实现了IFormPartCusomatorService
界面?如果您想每次启动新实例,您可以查看ExportFactory<ICustomRenderer, ICustomRendererMetadata>
.