满意导入一次vs组成部分 [英] SatisfyImportsOnce vs ComposeParts

查看:90
本文介绍了满意导入一次vs组成部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以解释一下SatisfyImportsOnceComposeParts之间的区别,以及为什么一个人可以在另一个人无法使用的地方工作吗?

Can someone please explain the difference between SatisfyImportsOnce and ComposeParts and why one would work where the other doesn't?

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

Specifically I have a MVC Web application that I am using MEF in. Below is some code (from that application) that works when I use SatisfyImportsOnce but doesn't when I use ComposeParts. My understanding is that ComposeParts creates composable parts from an array of attributed objects and composes them in the specified composition container and that SatisfyImportsOnce composes the specified part by using the specified composition service. To my simple monkey brain even though the English is different they are semantically the same. Both use the CompositionContainer to spit exported types at import targets.

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

推荐答案

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

SatisyImportsOnce will compose a type without registering it for recomposition. So, if you intend to use a type without support for recomposition, you can use SatisfyImportsOnce and it will do the work as usual, but any changes in the container (new parts added, or parts removed), then your instance won't automatically be recomposed to offer up these new parts.

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

In your instance, you are using:

[ImportMany(typeof(ICustomRenderer), AllowRecomposition = true)]

...但是通过SatisfyImportsOnce,此导入将不会重新构成.

...but through SatisfyImportsOnce, this import won't be recomposed.

如果您不担心重组,则可以使用构造函数注入来更改代码,因此可以执行以下操作:

If you are not worried about recomposition, you could change your code use constructor injection, so you could do:

[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>实例集是您的类型需要的显式依赖关系,因此最好以可用状态实例化您的类型,而不是先实例化然后再添加一个步骤以准备好首次使用.

The reason I would suggest constructor injection, is that the set of Lazy<ICustomRenderer, ICustomRendererMetadata> instances are an explicit dependency your type requires, so it would be better to instantiate your type in a usable state, rather than instantiate and then require an additional step to get it ready for first time use.

这使您的FormPartCustomatorFactory类型更具可测试性.为此,如果您要按原样更改构造函数,则使它成为单例的方法将行不通.相反,您可以利用MEF的生命周期管理功能,因此可以将类型重新设计为:

This makes your FormPartCustomatorFactory type much more testable. To this end, if you were to change the constructor as such, then your method of making it a singleton wouldn't work. Instead, you could take advantage of the lifetime management functionality of MEF, so possibly redesign your type as:

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的实例,也可以导入相同的单例实例.

Doing it this way means that your type is not dependent on MEF, it can be used without it, its more testable, and the CompositionContainer will manage the lifetime of the part, in this case the CreationPolicy.Shared (which is the default for exported types), uses a singleton lifetime strategy. You can then import an instance of IFormPartCustomator, you import the same singleton instance.

我还要指出,将其称为Factory可能是错误的,因为工厂旨在创建新实例,而您的类型将仅为每个ICustomRenderer创建一个实例.如果这是预期的行为,也许最好将其称为实现了IFormPartCusomatorService接口的FormPartCustomatorService?如果您想每次启动新实例,可以查看ExportFactory<ICustomRenderer, ICustomRendererMetadata>.

I would also argue that calling it a Factory is possibly wrong, as a factory is designed to create new instances, whereas, your type will only create one instance of each ICustomRenderer. If this is the intended behaviour, maybe it would be better called an FormPartCustomatorService, that implements an IFormPartCusomatorService interface? If you want to spin up new instances each time, you could look at ExportFactory<ICustomRenderer, ICustomRendererMetadata>.

这篇关于满意导入一次vs组成部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆