插件的好处不用多说,只要接口一样,可以任意更换表现形式。
步骤如下:
1. 新建一个类库工程MyPlug。
默认创建Class1.cs文件,此类用于继承接口,并处理接口方法。
a. 在该工程中新建类Iplugin,并定义接口,代码如下:
namespace MyPlug
{
public interface Iplugin
{
void OnShowDlg(int No);//No表示要显示几号窗口
string OnShowInfo();
}
}
b.在该工程中新建两个窗体,Form1,Form2。界面如下
Form1 Form2
c. 在刚才的Class1.cs中继承上述接口,并实现方法
namespace MyPlug
{
public class Class1 : Iplugin
{
public void OnShowDlg(int No)
{
Form form;
switch(No)
{
case 2:
form = new Form2();
break;
default:
form = new Form1();
break;
}
form.ShowDialog();
}
public string OnShowInfo()
{
return "sylf-form:My";
}
}
}
d. 生成解决方案,获得动态链接库dll。后续会修改dll的输出路径
2. 在该解决方案中新建一个form窗体工程plugDemo
a.新建一个类 PluginLoader,专门处理动态链接库的加载和反射获取dll的实例:
(记得把刚才类库的输出路径改成现在这个窗体工程的Debug的plugin目录,方法就是右键上述类库的工程,选择属性,在生成选项卡的输出部分选择输出路径为这个窗体工程的Debug的plugin目录,就可以了。
或者把上述类库生成的dll手动拷贝到这个窗体工程的Debug的plugin目录,也是可以的。)
namespace plugDemo
{
public static class PluginLoader
{
public static ArrayList plugins = new ArrayList();
/// <summary>
/// 判断DLL中是否继承了Iplugin接口
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
private static bool IsValidPlugin(Type t)
{
bool ret = false;
Type[] interfaces = t.GetInterfaces();
foreach (Type item in interfaces)
{
if (item.FullName.IndexOf( "Iplugin")>=0)
{
ret = true;
break;
}
}
return ret;
}
/// <summary>
/// 加载插件,这里是在程序的Debug的plugin目录中搜索插件
/// </summary>
public static void LoadAllPlugins()
{
string[] files = Directory.GetFiles(Application.StartupPath + "\\plugin\\");
foreach (string file in files)
{
string ext = file.Substring(file.LastIndexOf("."));
if (ext != ".dll")
continue;
try
{
//加载插件的动态链接库
Assembly tmp = Assembly.LoadFile(file);
Type[] types = tmp.GetTypes();
foreach (Type t in types)
{
if (IsValidPlugin(t))//这两个if的功能是一样的
//if (t.GetInterface("Iplugin") != null)//判断该dll是否继承了Iplugin接口
{// 通过反射实例化
plugins.Add(tmp.CreateInstance(t.FullName));
}
}
}
catch (Exception err)
{
throw err;
}
}
}
}
}
b. 定义该工程的窗口界面如下:
c. 响应按钮“载入插件”点击事件
namespace plugDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
textBox_FormNo.Text = "1";
label_Error.Text = "";
}
private void button1_Click(object sender, EventArgs e)
{
if (Convert.ToInt32(textBox_FormNo.Text)>2 && Convert.ToInt32(textBox_FormNo.Text)<1)
{
label_Error.Text = "输入的窗口号不正确,强制为1号窗口";
textBox_FormNo.Text = "1";
}
PluginLoader.LoadAllPlugins();
if (PluginLoader.plugins.Count>0)
{
object obj = PluginLoader.plugins[0];
Type t = obj.GetType();<span style="color:#cc33cc;">
MethodInfo OnShowDlg = t.GetMethod("OnShowDlg");<span style="color:#000000;">//获取dll中的方法名</span></span><span style="color:#cc33cc;">
OnShowDlg.Invoke(obj, new object[] { Convert.ToInt32(textBox_FormNo.Text) });</span>
}
}
}
}
d. 至此,生成解决方案就可以运行了。
3. 说明
OnShowDlg如果没有参数,就是OnShowDlg.Invoke(obj,null);
如果有参数记得要传参数。如上面的示例,参数是int,换成Invoke的表达方式就好了。