用C#实现一个插件架构的系统

liuzuofei 2007-10-11 04:47:40
各位:由于系统的特殊性,现在有一个系统如下设计:
1.将业务模块做成dll,根据需要加载,
2.将dll以xml文件形式配置,根据需要配置,
3.系统加载dll,并根据dll的功能并动态生成菜单项。
4.菜单事件由dll自己实现,
问题是在动态创建菜单时,需要指定菜单事件,如何将dll中的菜单事件指派到该创建的菜单上那??
如下:
sysMenu.Click += new EventHandler(Dll_Menu_Click);
Dll_Menu_Click函数在dll是实现,

希望各位大侠有好的建议和想法,共同讨论......
...全文
1151 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
不老神仙 2010-08-17
  • 打赏
  • 举报
回复
学习了 谢谢
tommyhuanglei 2008-01-31
  • 打赏
  • 举报
回复
我参考一下
liuzuofei 2007-10-22
  • 打赏
  • 举报
回复
谢谢大家如此热情,希望和我一样的朋友有收获,继续顶,让更多的人学习。
IThurricane 2007-10-19
  • 打赏
  • 举报
回复
up
学习一下
x_coolboy 2007-10-18
  • 打赏
  • 举报
回复
看看SharpDevelop,原作者参加过Eclipse核心代码的开发
相当于用C#重写了一遍Eclipse,结构非常好,不过占内存

我前年开发的项目就是基于SharpDevelop的,还不错
wsj1983920 2007-10-17
  • 打赏
  • 举报
回复
up 学习中
shinaterry 2007-10-17
  • 打赏
  • 举报
回复
制定接口...

实现, 再利用反射加载DLL就可以了...

^o^
billy_zh 2007-10-17
  • 打赏
  • 举报
回复
可以看看SharpDeveloper的实现。
3000sunqin 2007-10-17
  • 打赏
  • 举报
回复
/// <summary>
/// 注销Plug-in模块
/// </summary>
/// <param name="plugID">Plug-in模块的名称</param>
public void UnRegisterPlugIn(string plugID)
{
if (Contains(plugID))
{
//在对Plug-in列表进行访问时应该锁定,以防止多线程时出现问题
lock (lockObject)
{
PlugInRegisterEntity objPlugInRegisterEntity = plugIns[plugID];
if ((objPlugInRegisterEntity.PlugInObject != null) && (objPlugInRegisterEntity.PlugInObject is IDisposable))
{
((IDisposable)objPlugInRegisterEntity.PlugInObject).Dispose();
}
plugIns.Remove(plugID);
}
}
}

/// <summary>
/// 使用缺省的Plug-in模块内容提供者载入所有已经注册过的PlugIn模块列表
/// </summary>
public void LoadPlugInObjectList()
{
//使用Plug-In模块内容提供者来提供所有对Plug-In模块的存储到介质,以及从介质读取的操作
IPlugInContentProvider plugInContentProvider;
plugInContentProvider = PlugInContentProviderFactory.CreatePlugInContentProvider();
LoadPlugInObjectList(plugInContentProvider);
}

/// <summary>
/// 使用指定的Plug-in模块内容提供者载入所有已经注册过的PlugIn模块列表
/// </summary>
/// <param name="plugInContentProvider">指定的Plug-in模块内容提供者对象</param>
public void LoadPlugInObjectList(IPlugInContentProvider plugInContentProvider)
{
if (plugInContentProvider == null)
throw new ArgumentNullException(Resources.ProviderIsNull);
lock (lockObject)
{
plugIns = plugInContentProvider.GetAllPlugInObjects();
}
}

/// <summary>
/// 使用缺省的Plug-in模块内容提供者保存Plug-in对象列表
/// </summary>
public void SavePlugInObjectList()
{
IPlugInContentProvider plugInContentProvider;
plugInContentProvider = PlugInContentProviderFactory.CreatePlugInContentProvider();
SavePlugInObjectList(plugInContentProvider);
}

/// <summary>
/// 使用指定的Plug-in模块内容提供者保存Plug-in对象列表
/// </summary>
/// <param name="plugInContentProvider">指定的Plug-in模块内容提供者对象</param>
public void SavePlugInObjectList(IPlugInContentProvider plugInContentProvider)
{
if (plugInContentProvider == null)
throw new ArgumentNullException(Resources.ProviderIsNull);
lock (lockObject)
{
plugInContentProvider.DeleteAllPlugInObjects();
plugInContentProvider.SaveAllPlugInObjects(plugIns);
PlugIns.Clear();
LoadPlugInObjectList(plugInContentProvider);
}
}

/// <summary>
/// 使用缺省的Plug-in模块内容提供者删除所有的Plug-in对象列表
/// </summary>
public void DeleteAllPlugInObject()
{
IPlugInContentProvider plugInContentProvider;
plugInContentProvider = PlugInContentProviderFactory.CreatePlugInContentProvider();
DeleteAllPlugInObject(plugInContentProvider);
}

/// <summary>
/// 使用指定的Plug-in模块内容提供者删除所有的Plug-in对象列表
/// </summary>
/// <param name="plugInContentProvider">指定的Plug-in模块内容提供者对象</param>
public void DeleteAllPlugInObject(IPlugInContentProvider plugInContentProvider)
{
if (plugInContentProvider == null)
throw new ArgumentNullException(Resources.ProviderIsNull);
lock (lockObject)
{
plugInContentProvider.DeleteAllPlugInObjects();
PlugIns.Clear();
}
}

}
}
3000sunqin 2007-10-17
  • 打赏
  • 举报
回复
/*----------------------------------------------------------------
// Copyright (C) 2007 METTLER TOLEDO (CHANGZHOU) SCALE & SYSTEM LTD.
// 版权所有。
//
// 文件名:PlugInContext.cs
// 路径:MTFramework.Base\PlugInManager\PlugInContext.cs
// 文件功能描述:负责管理所有Plug-in模块的类
//
//
// 创建标识:sunqin20070806
//
// 修改标识:
// 修改描述:
//
//----------------------------------------------------------------*/

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using MTFramework.Base.PlugInManager.Exceptions;
using MTFramework.Base.Properties;

namespace MTFramework.Base.PlugInManager
{
/// <summary>
/// 负责管理所有Plug-in模块的创建和获取
/// </summary>
public class PlugInContext
{
//用于存放所有可插入模块的容器
private Dictionary<string, PlugInRegisterEntity> plugIns = new Dictionary<string, PlugInRegisterEntity>();

//指向自身的引用,本类将实现Singleton设计模式
private static PlugInContext instance;
//用于应对多线程访问所预备的锁对象
private static Object lockObject = new Object();

//使用私有的构造器来覆盖缺省的公共构造器,实现Singleton模式
private PlugInContext()
{
}

public Dictionary<string, PlugInRegisterEntity> PlugIns
{
get { return plugIns; }
}
/// <summary>
/// 获得当前Plug-in模块管理对象
/// </summary>
public static PlugInContext Instance
{
get
{
lock (lockObject)
{
if (instance == null)
instance = new PlugInContext();
return instance;
}

}
}

/// <summary>
/// Plug-in模块的索引器
/// </summary>
/// <param plugID="plugID">Plug-in模块的名称</param>
/// <returns></returns>
public IPlugObject this[string plugID]
{
get
{
if (!plugIns.ContainsKey(plugID)) return null;
PlugInRegisterEntity objPlugInEntity = plugIns[plugID];
if (objPlugInEntity.PlugInObject == null)
{
try
{
//利用反射方式来构建Plug-in模块的对象
ConstructorInfo ci = objPlugInEntity.ClassType.GetConstructor(new System.Type[] { });
IPlugObject plugObject = (IPlugObject)ci.Invoke(null);
if (plugObject != null)
objPlugInEntity.PlugInObject = plugObject;
}
catch
{
return null;
}
}
return (IPlugObject)(plugIns[plugID].PlugInObject);
}
}

/// <summary>
/// 判断是否存在指定名称的Plug-in模块
/// </summary>
/// <param plugID="plugID">Plug-in模块的名称</param>
/// <returns>是否存在标志(布尔值)</returns>
public bool Contains(string plugID)
{
return plugIns.ContainsKey(plugID);
}

/// <summary>
/// 注册Plug-in模块,本方法不会覆盖已有的Plug-in对象
/// </summary>
/// <param name="plugID">Plug-in模块的名称</param>
/// <param name="assemblyName">Plug-in模块所属程序集的名称</param>
/// <param name="type">Plug-in模块的类型</param>
/// <param name="PlugInType">Plug-in模块所实现接口的类型</param>
/// <exception cref="PlugInObjectAlreadyExistException">所指定的Plug-in模块已经在列表中存在</exception>
public void RegisterPlugInObject(string plugID, string assemblyName, Type type, string plugInType,string description)
{
RegisterPlugInObject(plugID, assemblyName, type, plugInType,description, false);
}

/// <summary>
/// 注册Plug-in模块
/// </summary>
/// <param name="plugID">Plug-in模块的名称</param>
/// <param name="assemblyName">Plug-in模块所属程序集的名称</param>
/// <param name="type">Plug-in模块的类型</param>
/// <param name="PlugInType">Plug-in模块所实现接口的类型</param>
/// <param name="overwrite">是否覆盖原有的Plug-in对象</param>
/// <exception cref="PlugInObjectAlreadyExistException">所指定的Plug-in模块已经在列表中存在</exception>
public void RegisterPlugInObject(string plugID, string assemblyName, Type type, string plugInType,string description, bool overwrite)
{
//在对Plug-in列表进行访问时应该锁定,以防止多线程时出现问题
lock (lockObject)
{
if (Contains(plugID))
{
if (!overwrite)
throw new PlugInObjectAlreadyExistException(plugID);
else
{
//如果需要覆盖原有的Plug-in对象,则需要先将原有的Plug-in对象销毁
PlugInRegisterEntity objPlugInRegisterEntity = plugIns[plugID];
if ((objPlugInRegisterEntity.PlugInObject != null) && objPlugInRegisterEntity.PlugInObject is IDisposable)
{
((IDisposable)objPlugInRegisterEntity.PlugInObject).Dispose();
}
objPlugInRegisterEntity.AssemblyName = assemblyName;
objPlugInRegisterEntity.ClassType = type;
objPlugInRegisterEntity.PlugInType = plugInType;
objPlugInRegisterEntity.PlugInObject = null;
}
}
else
plugIns.Add(plugID, new PlugInRegisterEntity(assemblyName, type, plugInType));
}
}
3000sunqin 2007-10-17
  • 打赏
  • 举报
回复
/*----------------------------------------------------------------
// Copyright (C) 2007 METTLER TOLEDO (CHANGZHOU) SCALE & SYSTEM LTD.
// 版权所有。
//
// 文件名:IPlugObject.cs
// 路径:MTFramework.Base\PlugInManager\IPlugObject.cs
// 文件功能描述:本接口为所有需要Plug-in功能的模块所需要实现的接口
//
//
// 创建标识:sunqin20070806
//
// 修改标识:
// 修改描述:
//
//----------------------------------------------------------------*/



using System;
using System.Collections.Generic;
using System.Text;

namespace MTFramework.Base.PlugInManager
{
/// <summary>
/// 本接口为所有需要Plug-in功能的模块所需要实现的接口
/// </summary>
public interface IPlugObject
{
/// <summary>
/// 用于识别Plug-in对象,当需要使用Plug-in对象时需要提供该标识,该标识应该唯一
/// </summary>
string PlugID { get;set;}
}
}


/*----------------------------------------------------------------
// Copyright (C) 2007 METTLER TOLEDO (CHANGZHOU) SCALE & SYSTEM LTD.
// 版权所有。
//
// 文件名:IPlugInForm.cs
// 路径:MTFramework.Base\PlugInManager\IPlugInForm.cs
// 文件功能描述:本接口为所有需要具备Plug-in特性的窗体所需要实现的接口
//
//
// 创建标识:sunqin20070806
//
// 修改标识:
// 修改描述:
//
//----------------------------------------------------------------*/


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms ;


namespace MTFramework.Base.PlugInManager
{
/// <summary>
/// 所有需要具备Plug-in特性的窗体所需要实现的接口
/// </summary>
public interface IPlugInForm :IPlugObject
{
/// <summary>
/// 标识本窗体是否为MDI子窗体
/// </summary>
bool IsMDIChild { get;}

/// <summary>
/// 标识本窗体是否为对话框
/// </summary>
bool IsDialog { get;}

/// <summary>
/// 指向真实的Form对象引用
/// </summary>
Form FormObject { get;}
}
}
3000sunqin 2007-10-17
  • 打赏
  • 举报
回复
最近正好写了一个这样的东西,贴点代码出来
/// <summary>
/// Plug-in模块描述信息的实体类
/// </summary>
public class PlugInRegisterEntity
{
private string assemblyName;
/// <summary>
/// 类所属程序集名称
/// </summary>
public string AssemblyName
{
get { return assemblyName; }
set { assemblyName = value; }
}

private Type classType;
/// <summary>
/// 可插入类的类型
/// </summary>
public Type ClassType
{
get { return classType; }
set { classType = value; }
}

private object plugInObject;
/// <summary>
/// 可插入类的实例
/// </summary>
public object PlugInObject
{
get { return plugInObject; }
set { plugInObject = value; }
}



private string plugInType;
/// <summary>
/// 所实现的可插入接口的类型名称
/// </summary>
public string PlugInType
{
get { return plugInType; }
set { plugInType = value; }
}


/// <summary>
/// 构造函数
/// </summary>
/// <param name="assemblyName">程序集名称</param>
/// <param name="classType">插入模块的类型</param>
/// <param name="PlugInType">所实现的可插入接口的类型名称</param>
public PlugInRegisterEntity(string assemblyName, Type classType, string plugInType)
{
this.assemblyName = assemblyName;
this.ClassType = classType;
this.PlugInType = plugInType;
this.plugInObject = null;
}
}
liuzuofei 2007-10-12
  • 打赏
  • 举报
回复
还是希望大侠给一份详细的demo,万分感谢!Q
xiangyyy 2007-10-12
  • 打赏
  • 举报
回复
象普元的东西。

XML配置
九章落地 2007-10-12
  • 打赏
  • 举报
回复
楼主了解一下反射的知识,也不是很复杂,我贴其中的两种方式出来,功能是返回一个订单接口IOrder


//方法一
//"SQLServerDAL"是指模块所在的命名空间
IOrder order = Assembly.Load("SQLServerDAL").CreateInstance("SQLServerDAL.Order") as IOrder;


//方法二
//"SQLServerDAL.DLL"是指模块所在的DLL
IOrder order = Assembly.Load("SQLServerDAL.DLL").CreateInstance("SQLServerDAL.Order") as IOrder;

3000sunqin 2007-10-12
  • 打赏
  • 举报
回复
该问题可以解决,但是代码太多,不好贴上来
liuzuofei 2007-10-12
  • 打赏
  • 举报
回复
谢谢两位,
private void Menu_Click(object sender, EventArgs e)
{
//这里通过反射调用相应的DLL中的方法
}
能不能具体写一段例子?非常期待!!
liuzuofei 2007-10-12
  • 打赏
  • 举报
回复
谢谢,反射的功能完成了,但是还有一个问题:
switch (plug.action_type)
{
case "add":
if (plug.id == "CBBADA5F-836A-4333-9450-2F52637FB187")
{
//利用反射机制,定义回调函数
Assembly ass = Assembly.LoadFrom(plug.plug_file);
Type type = ass.GetType("Plugins.plugA");
IPluginInterface pi = Activator.CreateInstance(type) as IPluginInterface;
newMenu.Click += new EventHandler(pi.AddObject);
}
break;
default:
MessageBox.Show("error");
break;

}

但是这样一点也不灵活,如何才能不用case和if判断这种硬编码,而自动的自动事件??
crystaller 2007-10-11
  • 打赏
  • 举报
回复
这不是个简单的问题,笼统的来说
先要写好接口,这步最关键了,如果写的好那就容易的多了
再继承特定的接口
然后利用反射调用dll
lovefootball 2007-10-11
  • 打赏
  • 举报
回复
sysMenu.Click += new EventHandler(this.Menu_Click);

private void Menu_Click(object sender, EventArgs e)
{
//这里通过反射调用相应的DLL中的方法
}

111,125

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧