接着上一篇文章:http://blog.csdn.net/joyhen/article/details/22905481
MEF:http://www.cnblogs.com/tcjiaan/tag/MEF/
原文:http://blog.csdn.net/jam12315/archive/2008/08/18/2791534.aspx
首先,新建一个类库,里面定义接口,这里定义两个方法,一个有返回值的,一个无返回值的。
using System;
using System.Collections.Generic;
using System.Text;
namespace IMsg {
///<summary>
/// 这是插件必须实现的接口,也是主程序与插件通信的唯一接口
/// 换句话说,主程序只认识插件里的这些方法
///</summary>
publicinterface IMsgPlug { void OnShowDlg(); string OnShowInfo();
}
}
将上面的类库生成IMsg.dll, 新建一个类库MYPlugin1,添加刚出的引用,分别新建两个类来实现IMsg中定义的接口。
using System;
using System.Collections.Generic;
using System.Text;
using IMsg;
namespace MYPlugin1 {
publicclass myConsole: IMsgPlug {#region IMsgPlug成员publicvoid OnShowDlg() {
Console.WriteLine("控制台调用插件的OnShowDlg方法");
}
publicstring OnShowInfo() {
return "myConsole";
}#endregion
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using IMsg;
namespace MYPlugin1 {
publicclass MYDlg: Form,
IMsgPlug {#region IMsgPlug成员
publicvoid OnShowDlg() {
this.Text = "插件子窗体";
this.ShowDialog(); //调用Form的ShowDialog,显示窗体
}
publicstring OnShowInfo() {
return "MyDlg";
}#endregion
}
}
将上面的都生成dll, 生成目录可以设置为新建exe工程的bin目录plugins文件夹下。Plugins文件夹是新建的,专门存放插件的。 新建一个 WinForm项目来使用刚才的插件.
using System;
using System.IO;
using System.Linq;
using System.Collections;
using System.Windows.Forms;
using System.Reflection;
namespace myConsole
{
public partial class Form1 : Form
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 存放插件的集合
/// </summary>
private ArrayList plugins = new ArrayList();
//载入所有插件
private void btnLoadPlug_Click(object sender, EventArgs e)
{
string[] files = Directory.GetFiles(Application.StartupPath + "\\plugins");
if (files != null)
this.listBox1.Items.Clear();
foreach (var f in files)
{
if (!f.ToUpper().EndsWith(".DLL"))
continue;
try
{
Assembly ab = Assembly.LoadFile(f);
Type[] t = ab.GetTypes();
foreach (var x in t)
{
if (x.GetInterface("IMsgPlug") != null)
{
plugins.Add(ab.CreateInstance(x.FullName));
this.listBox1.Items.Add(x.FullName);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
//调用插件的方法
private void btnExecute_Click(object sender, EventArgs e)
{
if (this.listBox1.SelectedIndex == -1)
return;
object selObj = this.plugins[this.listBox1.SelectedIndex];
Type t = selObj.GetType();
MethodInfo OnShowDlg = t.GetMethod("OnShowDlg");
MethodInfo OnShowInfo = t.GetMethod("OnShowInfo");
OnShowDlg.Invoke(selObj, null);
object returnValue = OnShowInfo.Invoke(selObj, null);
this.lblMsg.Text = returnValue.ToString();
}
}
}
运行结果:
此方法用了反射,个人感觉效果不是很好。另外,注意dll对象的依赖,这种问题我在手写上面demo的时候发现了,首先要保证依赖文件的存在,再一个依赖文件的路径需要正确。另一点要说下,对反射后的验证可以做一些加强处理,listbox对象显示的名字可以通过给dll中对象添加特性标记,然后获取显示出来。下一节我们看看MEF的小例子。
最后想说一下,这不是正在意义上的插件式开发,请参阅微软的MEF和MAF的设计