如何在Metro风格应用中获取导出值(MEF)

3

我意识到,MEF在Metro风格的应用程序中受到一定限制。现在不再有容器了,那么我该如何获得特定的导出值,比如ILogger logger = container.GetExportedValues<ILogger>();? 是否有任何教程介绍MEF的Metro版本?

谢谢帮助, Eny


你找到解决方案了吗?我最终使用了ExportFactory和SatisfyImportsOnce,但我对此不满意,我只需要GetExportedValues。 - ie.
我正在与一个开发MEF的地铁风格应用程序的人联系。他告诉我,SatisfyImportsOnce目前是组合项的唯一方法。他问我有哪些具体场景不受SatisfyImportOnce支持:http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/6aff302d-867a-4921-86ae-b8088c47560f我找到了一个暂时替代MEF的小工具:http://metroioc.codeplex.com/希望它也能帮到你。 - Enyra
我不想使用其他框架,因为我想在项目之间共享一些代码。而且,由于我已经在源项目中使用了MEF,所以我想继续使用它。我的需求并不是太大,所以我更喜欢添加缺失的功能。我会将我的当前解决方案作为答案添加。 - ie.
2个回答

2
我猜想你已经发现了System.CompononentModel.Composition和System.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将仅查询此程序集以查找导出的类型。还有其他类型的目录,我相信您应该能够将2个或更多目录组合在一起。

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

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

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

在这个例子中,您需要在该类上调用组合服务的SatisfyImportsOnce方法。我是在构造函数中这样做的:
if(App.CompositionService != null)
  App.CompositionService.SatisfyImportsOnce(this);

为确保服务存在而进行的检查是我过于谨慎了,实际上它应该是存在的。

在此步骤之后,您可以在类中实际使用Tester.Message属性。MEF中还有更多选项。我希望这可以帮助您(如果有帮助,请将我标记为答案,因为我从为客户计费的宝贵时间中抽出了时间来为您完成这项工作)。

我知道您希望简单地调用容器并让它返回某种类型的实例。使用其他形式的MEF可以做到这一点,因此我想它应该也可以在WinRT中实现,但是目前我并不确定。


你好,DevTheo。我已经弄清楚了,但不幸的是它并不完全符合我的要求。容器允许获取特定的导出值,而无需满足任何导入:container.GetExportedValue<IServiceLocator>(); 我正在寻找Metro MEF上的等效函数。 - Enyra
对不起,我没能为你解决问题... 我没有完全找到你想要的(而且像我说的需要回到客户工作 <微笑/>)。如果我有机会,我会再深入探究一下。我有另一个想法,但需要先试验一些东西才能确定。 - DevTheo
我不指望你替我完成它 ;) 我已经有一个想法,但是我还没有足够的时间 ^^ 但我认为这不能没有一些自定义代码来完成。 - Enyra

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

我现在不关心性能,但我猜以后会添加工厂提供者或工厂的缓存


这并不是一个坏的方法!只是有点遗憾我们必须自己编写这样的代码 :( 谢谢,伙计。 - Enyra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接