PRISM + MEF -- 如何指定要使用哪个导出?

9
基本上,我该如何指定要选择哪个实现? FooService.cs:
public interface IFooService
{
    Int32 GetFoo();
}

[Export(typeof(IFooService))]
public sealed class Foo100 : IFooService
{
    public Int32 GetFoo()
    {
        return 100;
    }
}


[Export(typeof(IFooService))]
public sealed class Foo200 : IFooService
{
    public Int32 GetFoo()
    {
        return 200;
    }
}

ClientViewModel.cs:

[Export()]
public class ClientViewModel : NotificationObject
{
    [Import()]
    private IFooService FooSvc { get; set; }

    public Int32 FooNumber
    {
        get { return FooSvc.GetFoo(); }
    }
}

Boostrapper.cs:

public sealed class ClientBootstrapper : MefBootstrapper
{
    protected override void ConfigureAggregateCatalog()
    {
        base.ConfigureAggregateCatalog();

        //Add the executing assembly to the catalog.
        AggregateCatalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
    }

    protected override DependencyObject CreateShell()
    {
        return Container.GetExportedValue<ClientShell>();
    }

    protected override void InitializeShell()
    {
        base.InitializeShell();

        Application.Current.MainWindow = (Window)Shell;
        Application.Current.MainWindow.Show();
    }
}

ClientShell.xaml.cs:

[Export()]
public partial class ClientShell : Window
{
    [Import()]
    public ClientViewModel ViewModel
    {
        get
        {
            return DataContext as ClientViewModel;
        }
        private set
        {
            DataContext = value;
        }
    }

    public ClientShell()
    {
        InitializeComponent();
    }
}

我不确定该如何设置我的应用程序以注入正确的内容(在这种情况下,我希望注入Foo100)。我知道可以让它们导出自己并指定一个Foo100而不是IFooService,但这是否是正确的方法?

3个回答

7
如果某个合同有多个导出项,则您必须导入所有这些项(通过声明具有 ImportMany 属性的集合类型属性),或通过为合同指定名称使合同更加具体化:
[Export("Foo100", typeof(IFooService))]
public sealed class Foo100 : IFooService
{
    public Int32 GetFoo()
    {
        return 100;
    }
}


[Export("Foo200", typeof(IFooService))]
public sealed class Foo200 : IFooService
{
    public Int32 GetFoo()
    {
        return 200;
    }
}

-

[Import("Foo100", typeof(IFooService)]
private IFooService FooSvc { get; set; }

啊,命名合约。我都忘了这个!很好的回答。 - dthorpe
有没有办法在运行时而不是编译时决定使用哪个命名合约? - michael
@michael - 是的,但你需要一个对MEF的CompositionContainer的引用。然后你就可以调用container.GetExportedValue<T>("your_dynamic_contract_name")。 - Pavlo Glazkov
不熟悉MEF;但是这个概念看起来与Unity中的相同。 - Aaron McIver
@Aeron - 你说得完全正确,MEF在作为IoC/DI框架时与Unity相似。但是MEF不止于此。 - Pavlo Glazkov

3

我认为在MEF中,你无法指定你的单例导入仅绑定到Foo200实现。

你可以将导入属性声明为IEnumerable,然后通过枚举选择来选择你想要在自己的代码中使用的实现,或者确保IFooSvc的两个实现驻留在不同的程序集中,并且在定义MEF目录时只包括其中一个程序集。


1

我对MEF不太熟悉,所以可能有些偏差,但是使用Prism和Unity作为DI容器,您可以通过RegisterType方法指定关联。当您有多个实现单一接口的具体类型时,您可以为它们关联一个名称以进行区分。

IUnityContainer.RegisterType<IFooService, Foo100>("Foo100");
IUnityContainer.RegisterType<IFooService, Foo200>("Foo200");

然后当您想要解决给定的实例时,可以执行...

IUnityContainer.Resolve<IFooService>("Foo200");

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