有没有人使用过 Microsoft 的托管可扩展性框架 (MEF)?有点像它试图成为所有人的一切 - 它是一个加载项管理器!这是鸭子打字!我想知道是否有人对此有经验,无论是积极的还是消极的。
我们目前正计划在我们的下一个大项目中使用通用 IoC 实现 ala MvcContrib。我们应该把 MEF 加入其中吗?
我们的目标不是让 MEF 成为一个通用的 IoC。考虑 MEF 的 IoC 方面的最佳方式是实现细节。我们使用 IoC 作为一种模式,因为它是解决我们希望解决的问题的好方法。
MEF 专注于可扩展性。当您想到 MEF 时,请将其视为推动我们平台向前发展的投资。我们未来的产品和平台将利用 MEF 作为增加可扩展性的标准机制。第三方产品和框架也将能够利用同样的机制。MEF 的普通“用户”将编写 MEF 将使用的组件,并且不会在其应用程序中直接使用 MEF。
想象一下,当您将来想要扩展我们的平台时,您将一个 dll 放入 bin 文件夹中,您就完成了。启用 MEF 的应用程序会随着新的扩展而亮起。这就是 MEF 的愿景。
这篇文章是指托管可扩展性框架预览版 2。
因此,我浏览了 MEF 并写了一个简短的“Hello World”,如下所示。我得说这很容易深入和理解。目录系统非常棒,让 MEF 本身的扩展变得非常简单。将它指向插件程序集的目录并让它处理其余部分是微不足道的。MEF 的传统 ala Prism 肯定会体现出来,但我认为如果不这样做会很奇怪,因为这两个框架都是关于组合的。
我认为最让我印象深刻的是 _container.Compose() 的“魔力”。如果您查看 HelloMEF 类,您会发现 greetings 字段从未被任何代码初始化,这感觉很有趣。我认为我更喜欢 IoC 容器的工作方式,您明确要求容器为您构建一个对象。我想知道某种“Nothing”或“Empty”通用初始值设定项是否合适。IE
private IGreetings greetings = CompositionServices.Empty<IGreetings>();
这至少会用“某物”填充对象,直到容器组合代码运行以用真正的“某物”填充它。我不知道——它带有一点 Visual Basic 的 Empty or Nothing 关键字的味道,我一直不喜欢它。如果其他人对此有一些想法,我想听听他们的意见。也许这是我需要克服的。它标有一个大胖子[进口]属性,所以它不是一个完全的谜或什么的。
控制对象生命周期并不明显,但默认情况下一切都是单例,除非您将 [CompositionOptions] 属性添加到导出的类。那让你指定Factory或Singleton。很高兴看到在某个时候将 Pooled 添加到此列表中。
我不太清楚鸭子打字功能是如何工作的。它似乎更像是对象创建时的元数据注入,而不是鸭子类型。看起来你只能添加一只额外的鸭子。但就像我说的,我还不清楚这些功能是如何工作的。希望我以后可以回来填写。
我认为对 DirectoryPartCatalog 加载的 DLL 进行影子复制是个好主意。现在,一旦 MEF 获得 DLL,它们就会被锁定。这也将允许您添加目录观察程序并捕获更新的插件。那会很甜蜜...
最后,我担心插件 DLL 的可信度以及 MEF 如何或是否会在部分信任环境中运行。我怀疑使用 MEF 的应用程序需要完全信任。将插件加载到他们自己的 AppDomain 中也可能是谨慎的。我知道它有点 System.AddIn 的味道,但它允许用户插件和系统插件之间非常清晰的分离。
好吧——废话不多说。这是 MEF 和 C# 中的 Hello World。享受!
using System;
using System.ComponentModel.Composition;
using System.Reflection;
namespace HelloMEF
{
public interface IGreetings
{
void Hello();
}
[Export(typeof(IGreetings))]
public class Greetings : IGreetings
{
public void Hello()
{
Console.WriteLine("Hello world!");
}
}
class HelloMEF : IDisposable
{
private readonly CompositionContainer _container;
[Import(typeof(IGreetings))]
private IGreetings greetings = null;
public HelloMEF()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
_container = new CompositionContainer(catalog);
var batch = new CompositionBatch();
batch.AddPart(this);
container.Compose(batch);
}
public void Run()
{
greetings.Hello();
}
public void Dispose()
{
_container.Dispose();
}
static void Main()
{
using (var helloMef = new HelloMEF())
helloMef.Run();
}
}
}
关于 Andy 对 MEF 加载的扩展的安全性问题(对不起,我还没有足够的分数 :)),解决这个问题的地方是目录。MEF 目录是完全可插入的,因此您可以编写一个自定义目录,在加载之前验证程序集密钥等。如果您愿意,您甚至可以使用 CAS。我们正在寻找可能提供的钩子,让您无需编写目录即可执行此操作。但是,当前目录的源代码是免费提供的。我怀疑至少有人(可能在我们的团队中)会实现一个并将其放入 CodePlex 上的扩展/贡献项目中。
Duck typing 不会在 V1 中发布,尽管它在当前版本中。在未来的下降中,我们将用一种可插入的适配器机制来替换它,在这种机制中,人们可以挂上鸭子类型机制。我们查看鸭子类型的原因是为了解决版本控制场景。使用 Duck Typing,您可以删除出口商和进口商之间的共享引用,从而允许多个版本的合同并存。
Andy,我相信 Glenn Block 在 MSDN MEF 论坛上的这个帖子中回答了许多人(自然)这样的问题:
CompositionContainer 与传统 IoC 容器的比较。
在某种程度上,Artem 的上述回答相对于 MEF 背后的主要意图是正确的,即可扩展性而不是组合。如果您主要对组合感兴趣,请使用其他常见的 IoC 嫌疑人之一。另一方面,如果您主要关心可扩展性,那么引入目录、部件、元数据标记、鸭子类型和延迟加载都会带来一些有趣的可能性。此外,Krzysztof Cwalina 在这里解释了 MEF 和 System.Addins 如何相互关联。
Ayende 在这里也有一篇很好的文章:http: //ayende.com/Blog/archive/2008/09/25/the-managed-extensibility-framework.aspx
它不是控制容器的注入。它是插件支持框架。
我想说,考虑到它会挂起 .NET 4.0 框架中的“系统”命名空间,你不会错得太远。看看 MEF 如何演变以及 Hamilton Verissimo(城堡)对 MEF 的发展方向有何影响,将会很有趣。
如果它像鸭子一样嘎嘎叫,它可能只是当前 IoC 容器群的一部分......
在这篇文章和评论中对此进行了更详细的讨论
http://mikehadlow.blogspot.com/2008/09/managed-extensibility-framework-why.html