主要区别在于,通过统一,您将显式注册要在组合中使用的每个类:
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 有一个“稳定组合”的概念,这意味着当它在某个地方遇到缺失的依赖项时,它会简单地将部分标记为不可用,并且无论如何都会继续组合。
Stable composition can be quite useful,但它也使它成为very difficult to debug a failed composition。因此,如果您不需要动态发现部件和“稳定组合”,我会使用常规 DI 容器而不是 MEF。与 MEF 不同,常规 DI 容器会在缺少依赖项时为您提供清晰的错误消息。
还可以通过使用与 MEF 集成的 DI 容器(如 Autofac)来获得两全其美的效果。使用 Autofac 编写核心应用程序,使用 MEF 编写需要动态扩展的部分。