在我的项目中,我需要使用插件.但是要在我的项目中使用这些,我需要导入插件的引用.由于我不知道项目预先使用了多少或哪些插件,我想在我的项目中动态导入它们.
String path = Application.StartupPath;
string[] pluginFiles = Directory.GetFiles(path, "*.dll");
ipi = new IPlugin[pluginFiles.Length];
Assembly asm;
for (int i = 0; i < pluginFiles.Length; i++)
{
string args = pluginFiles[i].Substring(
pluginFiles[i].LastIndexOf("\\") + 1,
pluginFiles[i].IndexOf(".dll") -
pluginFiles[i].LastIndexOf("\\") - 1);
asm = Assembly.LoadFile(pluginFiles[i]);
Type[] types = asm.GetTypes();
Run Code Online (Sandbox Code Playgroud)
在这个代码示例中,我搜索了所有.dll文件并将它们放入字符串列表中.但是我现在如何加载所有这些dll文件?或者有没有办法使用这些DLL文件而不真正导入它们?
Col*_*ron 16
您需要将System.ComponentModel.Composition的引用添加到使用MEF的导入/导出功能的项目中.
首先,bootstrapper/loader(在我的例子中,我刚刚将它添加到Main类).
Program.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using MEFContract;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
var prgm = new Program();
// Search the "Plugins" subdirectory for assemblies that match the imports.
var catalog = new DirectoryCatalog("Plugins");
using (var container = new CompositionContainer(catalog))
{
// Match Imports in "prgm" object with corresponding exports in all catalogs in the container
container.ComposeParts(prgm);
}
prgm.DoStuff();
Console.Read();
}
private void DoStuff()
{
foreach (var plugin in Plugins)
plugin.DoPluginStuff();
}
[ImportMany] // This is a signal to the MEF framework to load all matching exported assemblies.
private IEnumerable<IPlugin> Plugins { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
IPlugin接口是导入和导出之间的契约.所有插件都将实现此接口.合同很简单:
IPlugin.cs:
namespace MEFContract
{
public interface IPlugin
{
void DoPluginStuff();
}
}
Run Code Online (Sandbox Code Playgroud)
最后,您可以在不同的程序集中创建任意数量的插件.它们必须实现合同接口,并且还要使用"导出"属性进行修饰,以向MEF指示它们应与任何相应的导入匹配.然后将dll放在"Plugins"文件夹中(此文件夹应与可执行文件位于同一位置).这是一个示例插件:
Plugin.cs:
using System;
using System.ComponentModel.Composition;
using MEFContract;
namespace Plugin
{
[Export(typeof(IPlugin))]
public class Plugin : IPlugin
{
public void DoPluginStuff()
{
Console.WriteLine("Doing my thing!");
}
}
}
Run Code Online (Sandbox Code Playgroud)
为了简单起见,我们假设 的所有实现都有IPlugin
默认构造函数(公共且无参数)。
也就是说,您确实想要找到实现此接口的所有类型并创建它们的实例。您在某种程度上是在正确的轨道上,但是您可以使用一点 LINQ 来极大地简化它:
String path = Application.StartupPath;
string[] pluginFiles = Directory.GetFiles(path, "*.dll");
ipi = (
// From each file in the files.
from file in pluginFiles
// Load the assembly.
let asm = Assembly.LoadFile(file)
// For every type in the assembly that is visible outside of
// the assembly.
from type in asm.GetExportedTypes()
// Where the type implements the interface.
where typeof(IPlugin).IsAssignableFrom(type)
// Create the instance.
select (IPlugin) Activator.CreateInstance(type)
// Materialize to an array.
).ToArray();
Run Code Online (Sandbox Code Playgroud)
也就是说,使用依赖注入框架可能会更好;它们通常允许动态加载和绑定到编译时未引用的程序集中的接口实现。
另外,虽然有点复杂(在我看来),但您可能想查看System.AddIn
名称空间,因为它们是专门为此目的而构建的。但是,如果您不必担心合约等的版本控制,则依赖项注入途径通常会容易得多。