问题原贴:
http://cloverprince.iteye.com/admin/blogs/481307
引用
4. 现有一个主程序用C#语言写成。现在要允许第三方开发人员编写扩展的类,约定第三方开发的类必须包含一个实现了某个已知接口(如interface IFooPlugin)的类,名称不限。如果要求第三方的类必须与主程序的二进制代码分开发布,把dll丢在某个文件夹内即可被动态装载使用,应如何实现?
回答:
每个插件作为一个程序集(Assembly),dll的形式。里面包含一个实现已知接口的类。使用Assembly.LoadFile()装载该插件,用Assembly.GetInterface()寻找程序集中实现了已知接口的类,用Activator.CreateInstance创建实例。
适用范围:
Mono2.0和Visual C# 2008中测试通过。反射机制自.NET 1.0开始就有。
实现:
先指定一个接口,比如叫Cloverprince.IPlugin。插件必须包含一个类,实现这个接口。
using System;
namespace Cloverprince
{
public interface IPlugin
{
String Name {get;set;} // 设定和获取名字
void Greet(); // 打招呼
}
}
创建一个插件。插件包含一个类,实现这个接口。
这个类叫HelloWorldPlugin.HelloWorld。
using System;
using Cloverprince;
namespace HelloworldPlugin
{
public class HelloWorld: Cloverprince.IPlugin
{
private String _Name;
public String Name {
get {
return _Name;
}
set {
_Name = value;
}
}
public void Greet() {
Console.WriteLine("Hello, {0}",Name);
}
}
}
这个类将被编译成一个dll程序集
另一个插件也类似的制作。
类名:GoodbyePlugin.GoodbyeWorld:
using System;
using Cloverprince;
namespace GoodbyePlugin
{
public class GoodbyeWorld: Cloverprince.IPlugin
{
public String Name { get;set; }
public void Greet() {
Console.WriteLine("Goodbye, {0}",Name);
}
}
}
编译成另一个dll。
现在,两个插件已经有了,只差一个主程序来读取这两个插件了。
主程序:
using System;
using System.IO;
using System.Reflection;
using Cloverprince;
namespace Main
{
class MainClass
{
private const String PLUGINS_PATH="plugins";
public static void Main(string[] args)
{
foreach(String fileName in Directory.GetFiles(PLUGINS_PATH,"*.dll"))
{
Assembly ass = Assembly.LoadFile(Path.GetFullPath(fileName));
foreach(Type t in ass.GetTypes()) {
if(t.GetInterface("Cloverprince.IPlugin") != null) {
IPlugin p = (IPlugin)Activator.CreateInstance(t);
p.Name="Cloverprince";
p.Greet();
}
}
}
}
}
}
以上,所有需要的文件齐备。
编译:
如上所述,每个插件编译成一个dll程序集,主程序随意。注意路径。
执行:
执行该程序需要的最小文件集(3个文件):
引用
.
|-- Main.exe
`-- plugins
|-- GoodbyeWorld.dll
`-- HelloworldPlugin.dll
执行:
Windows: Main 或者直接双击图标
Unix+Mono: mono Main.exe
引用
Goodbye, Cloverprince
Hello, Cloverprince
总结:
1. 主程序并不了解plugins目录中有多少插件。在运行时列举目录。
2. 主程序对每个plugins文件(比如叫HelloworldPlugin.dll)的了解只有:
- 这个程序集中有0个或多个类实现了IPlugin接口。
- 这个类拥有一个不带参数的构造方法。