如何在metro风格的应用程序中获取导出值(MEF)

时间:2012-03-01 19:38:09

标签: mef windows-runtime

我认识到,MEF仅限于地铁风格的应用程序。没有容器了,所以如何获得ILogger logger = container.GetExportedValues<ILogger>();等特定的导出值? 是否有任何教程可用于MEF的城域版本?

感谢您的帮助, ENY

2 个答案:

答案 0 :(得分:2)

我猜你发现了System.CompononentModel.CompositionSystem.CompononentModel.Composition.Hosting名称空间。

让我在这里给你一个简单的例子(看看你是否遗漏了什么)。

首先,您需要注入一个组件:

public interface IMefTest
{
   string Message {get;}
}

[Export(typeof(IMefTest))]
public class MefTest: IMefTest
{
   public string Message {get { return "Hello World"; }}
}

接下来,您需要设置CompositionService(这类似于容器,但不完全相同)。我们希望将它设置为可以与之交谈的地方,因为这将是您调用以满足导入的地方(在此之后的代码段中更多内容)。

我把它放在我的示例项目的App.xaml.cs中:

static System.ComponentModel.Composition.ICompositionService _compositionService = null;
public static System.ComponentModel.Composition.ICompositionService CompositionService
{
    get
    {
        if (_compositionService == null)
            ((App)App.Current).loadCompositionService();
         return _compositionService;
    }
}

private void loadCompositionService()
{
    // Create a catalog where MEF will search for exported parts to plugin
    var catalog = new System.ComponentModel.Composition.Hosting.AssemblyCatalog(GetType().GetTypeInfo().Assembly);
    _compositionService = catalog.CreateCompositionService();
}

关于此的一点信息。我们已经建立了一个程序集目录,这意味着MEF将只询问此程序集以查找导出的类型。还有其他类型的目录,我相信您应该能够将两个或更多目录组合在一起。

好的,在我的页面中(顺便说一下,我将它构建到MSDN上的入门文档中的C#HelloWorld示例中)。

要获取目录中某个部分的实例,您只需要向要获取的类添加属性并添加一个imports属性(还有一些方法可以让它在构造函数上指定参数,但是我我想保持简单。

[Import]
public IMefTest Tester { get; set; }

在此示例中,您需要在此类上调用合成服务的SatisfyImportsOnce方法。我在构造函数中这样做了,我这样做了:

if(App.CompositionService != null)
  App.CompositionService.SatisfyImportsOnce(this);

(检查以确保服务存在对我来说是过度的..它应该存在)。 在该步骤之后,您实际上可以使用您班级中的Tester.Message属性。 MEF中有更多选项。我希望这可以帮助你(如果它确实是你的答案,因为我从计费客户那里花了宝贵的时间为你做这件事)

另外,我知道你想简单地调用一个容器并让它返回某种类型的实例。使用其他形式的MEF可以做到这一点,所以我想它应该可以用WinRT来完成,但我现在真的不确定。)

答案 1 :(得分:1)

正如我在评论中所写的那样,我并不喜欢这种方法,但这是我迄今为止最好的方法:

public class CompositionContainer
{
    private readonly CompositionService _service;

    public CompositionContainer(CompositionService service)
    {
        _service = service;
    }

    public T GetExportedValue<T>()
    {
        var factoryProvider = new FactoryProvider<T>();
        _service.SatisfyImportsOnce(factoryProvider);
        return factoryProvider.Factory.CreateExport().Value;
    }

    private class FactoryProvider<T>
    {
        [Import]
        public ExportFactory<T> Factory;
    }
}

和简单的用例可能就是这个:

class Program
{
    static void Main()
    {
        var catalog = new ApplicationCatalog();
        var container = new CompositionContainer(catalog.CreateCompositionService());
        for (int i = 0; i < 5; i++)
        {
            var dude = container.GetExportedValue<IDude>();
            Console.WriteLine(dude.Say());
        }
    }
    public interface IDude
    {
        string Say();
    }

    [Export(typeof(IDude))]
    public class Eminem : IDude
    {
        private static int _instanceNo;
        private readonly string _phrase;

        public Eminem()
        {
            _instanceNo++;
            _phrase = string.Join(" ", Enumerable.Range(0, _instanceNo)
                .Select(_ => "yo!"));
        }

        public string Say()
        {
            return _phrase;
        }
    }
}

此刻我不关心性能,但我想我稍后会添加工厂提供商或工厂的缓存