【问题标题】:SatisfyImportsOnce vs ComposePartsSatisfyImportsOnce vs ComposeParts
【发布时间】:2011-06-21 01:12:48
【问题描述】:

有人能解释一下SatisfyImportsOnceComposeParts 之间的区别吗?为什么一个可以工作而另一个不能工作?

具体来说,我有一个使用 MEF 的 MVC Web 应用程序。下面是一些代码(来自该应用程序),在我使用 SatisfyImportsOnce 时有效,但在我使用 ComposeParts 时无效。我的理解是ComposeParts 从属性对象数组中创建可组合部分,并将它们组合在指定的组合容器中,SatisfyImportsOnce 使用指定的组合服务组合指定的部分。对于我简单的猴子大脑来说,即使英语不同,它们在语义上也是相同的。两者都使用CompositionContainer 在导入目标处吐出导出的类型。

public class FormPartCustomatorFactory
{

    [ImportMany(typeof(ICustomRenderer), AllowRecomposition = true)]
    private readonly List<Lazy<ICustomRenderer, ICustomRendererMetaData>> _rendererImports = new List<Lazy<ICustomRenderer, ICustomRendererMetaData>>();

    private readonly Dictionary<string, Lazy<ICustomRenderer, ICustomRendererMetaData>> _renderers;

    public static readonly FormPartCustomatorFactory Instance = new FormPartCustomatorFactory();

    static CompositionContainer _container;

    private FormPartCustomatorFactory()
    {
        using (var catalog = new DirectoryCatalog(HttpRuntime.BinDirectory, "*.dll"))
        {               
            _container = new CompositionContainer(catalog);
            _container.SatisfyImportsOnce(this); // <- Works
            // _container.ComposeParts(this); // DOESN'T Work
            _renderers = _rendererImports.ToDictionary(q => q.Metadata.Name, q => q);
        }
    }

    ~FormPartCustomatorFactory()
    {
        _container.Dispose();
    }

    public static ICustomRenderer Find(string name)
    {
        return Instance._renderers[name].Value;
    }
}

【问题讨论】:

    标签: c# mef


    【解决方案1】:

    SatisyImportsOnce 将组成一个类型而不注册它以进行重组。因此,如果您打算使用不支持重组的类型,您可以使用SatisfyImportsOnce,它会照常工作,但是容器中的任何更改(添加新部件或移除部件),那么您的实例将不会t 会自动重组以提供这些新部分。

    在您的实例中,您正在使用:

    [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&lt;ICustomRenderer, ICustomRendererMetadata&gt; 实例集是您的类型所需的显式依赖项,因此最好将您的类型实例化为可用状态,而不是实例化然后需要额外的准备好第一次使用。

    这使您的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,它可以在没有它的情况下使用,它更可测试,CompositionContainer 将管理部件的生命周期,在这种情况下CreationPolicy.Shared(它是导出类型的默认值),使用单例生命周期策略。然后你可以导入一个IFormPartCustomator 的实例,你导入同一个单例实例。

    我还认为称它为Factory 可能是错误的,因为工厂旨在创建新实例,而您的类型只会为每个ICustomRenderer 创建一个实例。如果这是预期的行为,也许最好称为FormPartCustomatorService,实现IFormPartCusomatorService 接口?如果您想每次都启动新实例,可以查看ExportFactory&lt;ICustomRenderer, ICustomRendererMetadata&gt;

    【讨论】:

      【解决方案2】:

      正如 Matthew 所提到的,SatisfyImportsOnce 没有注册该部分以进行重组。这意味着 MEF 容器不包含对该部件的引用。

      另外,SatisfyImportsOnce 只满足一个部件的导入,而忽略它的任何导出。 ComposeParts 也会将导出添加到容器中。

      【讨论】:

      • "ComposeParts 也会将导出添加到容器中。" - 这就是我要找的:)
      猜你喜欢
      • 2011-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      • 2011-09-18
      • 1970-01-01
      相关资源
      最近更新 更多