如何在.NET中加载插件?

我想提供一些在我的软件中创builddynamic加载插件的方法。 典型的方法是使用LoadLibrary WinAPI函数加载一个dll并调用GetProcAddress来获取指向该dll内部函数的指针。

我的问题是如何在C#/ .Net应用程序中dynamic加载插件?

Solutions Collecting From Web of "如何在.NET中加载插件?"

下面的代码片断(C#)构造了从应用程序路径中的类库(* .dll)中的Base派生的任何具体类的实例,并将它们存储在一个列表中。

 using System.IO; using System.Reflection; List<Base> objects = new List<Base>(); DirectoryInfo dir = new DirectoryInfo(Application.StartupPath); foreach (FileInfo file in dir.GetFiles("*.dll")) { Assembly assembly = Assembly.LoadFrom(file.FullName); foreach (Type type in assembly.GetTypes()) { if (type.IsSubclassOf(typeof(Base)) && type.IsAbstract == false) { Base b = type.InvokeMember(null, BindingFlags.CreateInstance, null, null, null) as Base; objects.Add(b); } } } 

编辑: 马特提到的类可能是一个更好的选择在.NET 3.5中。

从.NET 3.5开始,就有了一种正式的,可以从.NET应用程序创建和加载插件的方法。 这一切都在System.AddIn命名空间中。 有关更多信息,可以查看MSDN上的这篇文章: 加载项和扩展性

动态加载插件

有关如何动态加载.NET程序集的信息,请参阅此问题 (和我的答案 )。 下面是一些代码,用于加载创建AppDomain并将程序集加载到其中。

 var domain = AppDomain.CreateDomain("NewDomainName"); var pathToDll = @"C:\myDll.dll"; var t = typeof(TypeIWantToLoad); var runnable = domain.CreateInstanceFromAndUnwrap(pathToDll, t.FullName) as IRunnable; if (runnable == null) throw new Exception("broke"); runnable.Run(); 

卸载插件

插件框架的典型要求是卸载插件。 要卸载动态加载的程序集(例如插件和加载项),必须卸载包含的AppDomain 有关更多信息,请参阅卸载AppDomains上的MSDN上的这篇文章 。

使用WCF

有一个堆栈溢出问题和答案 ,描述如何使用Windows通信框架(WCF)创建一个插件框架。

现有的插件框架

我知道两个插件框架:

  • Mono.Add-ins – 正如在这个答案中提到的另一个问题 。
  • 托管加载项框架(MAF) – 这是Matt在他的回答中提到的System.AddIn名称空间。

有些人将管理扩展性框架(MEF)作为插件或插件框架讨论,事实并非如此。 有关更多信息,请参阅此StackOverflow.com问题和此StackOverflow.com问题 。

一个技巧是将所有插件等加载到自己的AppDomain中,因为运行的代码可能是恶意的。 自己的AppDomain也可以用来“过滤”你不想加载的程序集和类型。

 AppDomain domain = AppDomain.CreateDomain("tempDomain"); 

并将程序集加载到应用程序域中:

 AssemblyName assemblyName = AssemblyName.GetAssemblyName(assemblyPath); Assembly assembly = domain.Load(assemblyName); 

要卸载应用程序域:

 AppDomain.Unload(domain); 

是的,++到Matt和System.AddIn(有关System.AddIn的MSDN杂志的两篇文章可在这里和这里找到 )。 您可能希望了解.NET Framework将来可能发展的另一项技术,即Codeplex上的CTP版本中提供的托管扩展性框架 。

基本上你可以用两种方法做到这一点。

首先是导入kernel32.dll并使用之前使用的LoadLibrary和GetProcAddress:

 [DllImport("kernel32.dll")] internal static extern IntPtr LoadLibrary(String dllname); [DllImport("kernel32.dll")] internal static extern IntPtr GetProcAddress(IntPtr hmodulee, String procname); 

其次是以.NET方式进行:使用反射。 检查System.Reflection命名空间和以下方法:

  • Assembly.LoadFile
  • Assembly.GetType
  • Assembly.GetTypes
  • Type.GetMethod
  • MethodInfo.Invoke

首先通过它的路径加载程序集,然后通过它的名字得到类型(class),然后再次通过它的名字得到类的方法,最后调用带有相关参数的方法。

这篇文章有点旧,但是仍然适用于在应用程序中创建一个扩展性层:

让用户使用宏和插件为.NET应用程序添加功能