满足自定义ExportProvider中的导入

时间:2011-12-14 15:37:19

标签: mef

我想知道如何在我的自定义ExportProvider中拥有Imports。以下是我正在尝试做的一个例子:

public class MyExportProvider : ExportProvider
{
    private List<Export> _exports;

    [Import()]
    private IConfig _config;

    public MyExportProvider()
       base()
    {
        _exports = new List<Export>();
    }

    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition,
                                                          AtomicComposition composition)
    {
        if (!_exports.Any())
            Initialize();

        return _exports.Where(x => definition.IsConstraintSatisfiedBy(s.Definition);
    }

    private void Initialize()
    {
        var contractName = typeof(MyObject).FullName;

        var exportDefinition = new ExportDefinition(contractName, null);
        var export = new Export(exportDefinition, () => new MyObject(_config));

        _exports.Add(export);
    }
}

我在创建CompositionContainer时添加提供程序。

不幸的是,导入永远不会令人满意。我可以通过设置AllowDefaults = true来看到这一点,因此我的提供程序已创建,但_config始终为null。

如何配置容器和/或提供程序以便满足导入?

2 个答案:

答案 0 :(得分:2)

添加导出提供程序时,您仍在创建合成容器。因此,我不知道如何使用尚未创建的合成容器来导入自定义导出提供程序的部分。

我要做的是首先创建一个临时的CompositionContainer,用于创建MyExportProvider。

然后使用MyExportProvider创建第二个最终的CompositionContainer,它将由应用程序的其余部分使用。

修改

    // this is your real container, only shown here for reference
    CompositionContainer container;

    public void BootstrapContainerMethod()
    {           
        // Replace this part with the catalogs required to create your export provider.
        var catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new DirectoryCatalog("./bin", "*.dll")); 

        // Your temporary container, declared here in local scope
        // will be disposed because of using
        using (var bootstrapContainer = new CompositionContainer(catalog))
        {
            var myExportProvider = bootstrapContainer.GetExportedValue<IMyExportProvider>();

            // create your real container and optionnally add catalogs (not shown here)
            container = new CompositionContainer(myExportProvider);
        }
    }

您也可以从另一个角度考虑问题。您真的需要在自定义ExportProvider中进行导入吗?我不知道你的要求,但也许你可以在没有进口的情况下做到。

答案 1 :(得分:1)

作为双CompositionContainer解决方案的替代方案,您可以将其连接到单个导出提供程序中,并使用相同的容器将其自行组合。例如,我已经定义了以下合同及其导出:

public interface ILogger
{
    void Log(string message);
}

[Export(typeof(ILogger))]
public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
}

使用我的示例ExportProvider,我希望能够导入它的实例:

public class TestExportProvider : ExportProvider
{
    private readonly object _lock = new object();
    private bool _initialised;

    [Import]
    public ILogger Logger { get; set; }

    public void SetCompositionService(ICompositionService service)
    {
        if (service == null) throw new ArgumentNullException("service");

        lock (_lock)
        {
            if (!_initialised)
            {
                InitialiseProvider(service);
            }
        }
    }

    private void InitialiseProvider(ICompositionService service)
    {
        service.SatisfyImportsOnce(this);
        _initialised = true;
    }

    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
    {
        if (_initialised)
        {
            Logger.Log("Getting available exports for '" + definition.ContractName + "'");

            // Do work here.);
            return Enumerable.Empty<Export>();
        }

        return Enumerable.Empty<Export>();
    }
}

我提供ICompositionService的实例,CompositionContainer实现,我在调用SetCompositionService时执行首次初始化。它会检查它是否已经初始化,如果没有,则继续调用SatisfyImportsOnce方法。

我们会把它连接起来,就像这样:

// Build our catalog.
var catalog = new AssemblyCatalog(typeof(Program).Assembly);

// Create our provider.
var provider = new TestExportProvider();

// Create our container.
var container = new CompositionContainer(catalog, provider);

// Register the composition service to satisfy it's own imports.
provider.SetCompositionService(container);

显然你不能使用任何导入,你的ExportProvider将明确地为你创建,但对于其他一切,它应该有效。