MEF和Unity有什么不同和用途?

54
我刚开始学习 DI(我正在 WPF/Silverlight 上工作,但计划转移到 ASP.NET)。在阅读了一些网络上的 DI 文章后,我对两个框架——MEF 和 Unity 感到很感兴趣。我想知道它们在现实世界中的区别是什么,哪一个更适合使用。

可能是MEEF与任何IoC的重复问题。 - Palec
2个回答

65
主要的区别在于使用Unity时,您需要显式地注册您想在组合中使用的每个类:
var container = new UnityContainer();
container.RegisterType<IFoo,Foo>();
container.RegisterType<IBar,Bar>();
...
var program = container.Resolve<Program>();
program.Run();

而在MEF中,您需要使用属性标记类,而不是将它们注册到其他地方:

[Export(typeof(IFoo))]
public Foo
{
   ...
}

乍一看,这似乎只是一个小的语法差异,但实际上比这更重要。MEF旨在允许动态发现部件。例如,使用DirectoryCatalog,您可以设计应用程序,使您可以通过简单地将新的DLL放入应用程序文件夹来扩展它。

在此示例中,MEF将查找并实例化给定目录中具有[Export(typeof(IPlugin))]属性的所有类,并将这些实例传递给Program构造函数:

[Export]
public class Program
{
    private readonly IEnumerable<IPlugin> plugins;

    [ImportingConstructor]
    public Program(
       [ImportMany(typeof(IPlugin))] IEnumerable<IPlugin> plugins)
    {
        this.plugins = plugins;
    }

    public void Run()
    {
        // ...
    }
}

入口点:

public static void Main()
{
    using (var catalog = new DirectoryCatalog(".","*"))
    using (var container = new CompositionContainer(catalog))
    {
        var program = container.GetExportedValue<Program>();
        program.Run();
    }
}

为适应这样的动态组合场景,MEF有一个"稳定组合"的概念,这意味着当它遇到某个地方缺少依赖时,它会简单地将该部分标记为不可用,并继续进行组合。 稳定组合非常有用, 但也使得调试失败的组合非常困难。因此,如果您不需要部件的动态发现和"稳定组合",我建议使用普通的DI容器而不是MEF。与MEF不同,普通的DI容器将在缺少依赖项时给出明确的错误消息。
还可以通过使用与MEF集成的DI容器(例如Autofac)来兼顾两全。使用Autofac来组合核心应用程序,使用MEF来扩展需要动态扩展的部分。

1
我希望它是那么容易。不幸的是,事实并非如此。MEF让我头疼不已。它抛出了大量的“ImportCardinalityMismatchException”错误,这似乎与MEF在调试能力方面设计得非常糟糕有关。在错误代码中,我找不到任何关于无法组装导出的参考。我即将完全放弃使用MEF的尝试。 - Matt
3
@Freddy:你的评论不清楚针对我的回答的哪一部分。我明确写道,“调试未成功的组合非常困难”,并链接了我的博客文章。我在哪里说过这很容易? - Wim Coenen
抱歉如果我误解了,您发布了Main方法并说“简单地放置DLL”和“MEF将找到所有带有Export属性的类”,这实际上并不容易和直接。我已经因此烦恼了很久。关于调试的观点是公正的。我更多地是在谈论MEF并不像看您的代码示例时想象的那样容易使用。也许我在阅读您的答案时有了错误的印象。 - Matt
这应该有助于调试MEF:
  1. 配置Visual Studio调试器以在抛出异常时中断。
  2. 配置您的CompositionContainer对象以禁用拒绝。 https://msdn.microsoft.com/zh-cn/library/ff603380%28v=vs.110%29.aspx
- Jeson Martajaya
应该指出的是,MEF和Unity之间的差异是因为这些库服务于不同的目的。Unity是一个IoC容器,旨在用于DI。MEF虽然可以作为一个IoC容器来使用,但它并不是一个IoC容器,而是用于可扩展性。请参阅:https://learn.microsoft.com/en-us/dotnet/framework/mef/index。 - mrfelis

22

有很多选项可用于进行DI。首先,您应该意识到DI不是关于工具,而是关于模式和原则。您可以在没有工具的情况下很好地使用DI。如果您这样做,我们称它为“Poor Man's DI”。

但是,话虽如此,.NET有许多可用于DI的容器。Unity只是其中之一。

MEF看起来很像DI容器,但目前解决的是不同的问题——即可扩展性问题。它使用基于属性的发现机制,而不是组件的外部配置(所有DI容器都使用这种方式)。


9
读这个人的书吧!!它让我走上了依赖注入的正确之路 :D。http://www.manning.com/seemann/ - Domenic

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