反射在.NET中的简单应用(一)
2008-08-27 13:14
363 查看
反射在.NET的应用很广泛,我们可以利用反射动态加载程序集,动态的创建类型的实例,或从现有对象获取类型并调用其方法或访问其字段和属性。有关反射的更多信息请参考MSDN(http://msdn.microsoft.com/zh-cn/library/ms173183(VS.80).aspx)
下面我们举两个例子来简单的说明下在.NET中如何应用反射。
假设我们有个系统可以动态扩展其功能,我们可以采用如下方法实现。
我们有个配置文件,叫做Config.xml,格式如下:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<MenuTests>
<Menu Text="" ActionDll="" ActionType="" />
<Menu Text="" ActionDll="" ActionType="" />
</MenuTests>
</Root>
有个Form,通过加载这个XML文件来生成他的菜单
Menu节点的Text属性就是将来菜单显示的Text
ActionDll是点击菜单时调用的类的所在的DLL
ActionType是点击菜单时调用的类的全称(命名空间+类名)
通过这个XML文件,我们可以动态的加载后续开发的程序
加载这个XML文件,我们可以采用序列化的办法,当然你也可以采用其他办法
这时我们需要建两个辅助类,代码如下:
这个基类可以是一个abstract的,包含一个abstract的方法,代码如下:
public abstract class ReflecteAbstractBase
{
public ReflecteAbstractBase()
{
}
public abstract void Run();
}
这个基类只有一个构造函数和一个方法,继承他的类都要重写这个Run方法,然后我们在程序中利用反射去调用这个方法就可以了,当然可以根据你的需要在添加些其他的方法以及属性
假设我们后续开发的功能叫做RelecteTestProject,那么我们可以写下如下代码:
namespace RelecteTestApp
{
public class RelecteTestProject : ReflecteAbstractBase
{
public RelecteTestProject() : base()
{
}
public override void Run()
{
//这里是程序的入口,在这里可以添加你需要的代码
}
}
}
同时我们去修改那个配置文件:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<MenuTests>
<Menu Text="RelecteTestProject"
ActionDll="RelecteTestProject.dll"
ActionType="RelecteTestApp.RelecteTestProject" />
</MenuTests>
</Root>
好了,我们准备工作都做好了,下面来看看如何加载这个XML文件,并且动态的调用它的方法
在需要加载菜单的Form中,我们可以采用如下代码来实现菜单的加载:
XmlSerializer mySerializer = new XmlSerializer(typeof(MenuTestCollection));
FileStream myFileStream = new FileStream("Config.xml", FileMode.Open);
MenuTestCollection config = (MenuTestCollection)mySerializer.Deserialize(myFileStream);
myFileStream.Close();
MainMenu menu = new MainMenu();
menu.Name = "menu";
MenuItem mi = new MenuItem("test");
menu.MenuItems.Add(mi);
foreach (MenuTest menuTest in config.MenuTests)
{
MenuItem m = new MenuItem(menuTest.Text);
m.Tag = menuTest;
m.Click += new EventHandler(m_Click);
mi.MenuItems.Add(m);
}
this.Menu = menu;
在Menu的Click事件中我们就根据保存起来的Tag属性的MenuTest 对象来动态的创建实例以及调用Run方法
private void m_Click(object sender, EventArgs e)
{
MenuItem m = sender as MenuItem;
MenuTest mt = m.Tag as MenuTest;
Assembly assembly = Assembly.LoadFrom(mt.ActionDll);
object obj = assembly.CreateInstance(
mt.ActionType,
true,
BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public,
null,
null,
null,
null);
Type type = obj.GetType();
MethodInfo mi = type.GetMethod("Run");
mi.Invoke(obj, null);
}
好了,这个例子基本上就结束了,在这个例子中需要注意的地方是:
1、BindingFlags的作用,具体的定义请参考MSDN(http://msdn.microsoft.com/en-us/library/system.reflection.bindingflags.aspx)
2、假设你的Run方法需要接收参数或者有不同的重载,那么你在GetMethod的时候需要把参数的类型传进去,也就是调用type.GetMethod(sting name,Type[] types)这个重载
3、在我这个例子中,XML和DLL文件都是和Form所在的EXE放在一个目录下的
下面我们再举一个例子,这个问题是曾经一个网友提问过的。
假设我们有个按钮,如何获得这个按钮的Click事件所挂的所有的方法
比如我们有个按钮叫做btn,加载它的Click事件
this.btn.Click += new EventHandler(btn_Click);
一般我们只加载一个方法,但是也有的时候我们会加载很多方法,比如:
this.btn.Click += new EventHandler(btn1_Click);
this.btn.Click += new EventHandler(btn2_Click);
this.btn.Click += new EventHandler(btn3_Click);
现在我们想获得这个btn的Click事件的所有方法
其实也很简单,主要是利用反射来获得他的委托列表,主要代码如下:
PropertyInfo pi = (typeof(System.Windows.Forms.Button)).GetProperty("Events",
BindingFlags.Instance | BindingFlags.NonPublic);
EventHandlerList ehl = (EventHandlerList)pi.GetValue(btn, null);
FieldInfo fi = (typeof(Control)).GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic);
Delegate d = ehl[fi.GetValue(null)];
if (d != null)
{
System.Delegate[] dels = d.GetInvocationList();
for (int i = 0; i < dels.Length; i++)
{
string s = dels[i].Method.Name;
//d = System.MulticastDelegate.Remove(d, dels[i]);
}
}
//ehl[fi.GetValue(null)] = d;
如果把注释掉的内容去掉,则可以取消btn的Click事件的所有方法,当然你也可以根据你的需要来取消特定的方法
好了,关于反射的应用就说这么多吧,反射是比较有用的东西,但是不能过度的使用,否则多多少少的会影响到效率
下面我们举两个例子来简单的说明下在.NET中如何应用反射。
假设我们有个系统可以动态扩展其功能,我们可以采用如下方法实现。
我们有个配置文件,叫做Config.xml,格式如下:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<MenuTests>
<Menu Text="" ActionDll="" ActionType="" />
<Menu Text="" ActionDll="" ActionType="" />
</MenuTests>
</Root>
有个Form,通过加载这个XML文件来生成他的菜单
Menu节点的Text属性就是将来菜单显示的Text
ActionDll是点击菜单时调用的类的所在的DLL
ActionType是点击菜单时调用的类的全称(命名空间+类名)
通过这个XML文件,我们可以动态的加载后续开发的程序
加载这个XML文件,我们可以采用序列化的办法,当然你也可以采用其他办法
这时我们需要建两个辅助类,代码如下:
这个基类可以是一个abstract的,包含一个abstract的方法,代码如下:
public abstract class ReflecteAbstractBase
{
public ReflecteAbstractBase()
{
}
public abstract void Run();
}
这个基类只有一个构造函数和一个方法,继承他的类都要重写这个Run方法,然后我们在程序中利用反射去调用这个方法就可以了,当然可以根据你的需要在添加些其他的方法以及属性
假设我们后续开发的功能叫做RelecteTestProject,那么我们可以写下如下代码:
namespace RelecteTestApp
{
public class RelecteTestProject : ReflecteAbstractBase
{
public RelecteTestProject() : base()
{
}
public override void Run()
{
//这里是程序的入口,在这里可以添加你需要的代码
}
}
}
同时我们去修改那个配置文件:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<MenuTests>
<Menu Text="RelecteTestProject"
ActionDll="RelecteTestProject.dll"
ActionType="RelecteTestApp.RelecteTestProject" />
</MenuTests>
</Root>
好了,我们准备工作都做好了,下面来看看如何加载这个XML文件,并且动态的调用它的方法
在需要加载菜单的Form中,我们可以采用如下代码来实现菜单的加载:
XmlSerializer mySerializer = new XmlSerializer(typeof(MenuTestCollection));
FileStream myFileStream = new FileStream("Config.xml", FileMode.Open);
MenuTestCollection config = (MenuTestCollection)mySerializer.Deserialize(myFileStream);
myFileStream.Close();
MainMenu menu = new MainMenu();
menu.Name = "menu";
MenuItem mi = new MenuItem("test");
menu.MenuItems.Add(mi);
foreach (MenuTest menuTest in config.MenuTests)
{
MenuItem m = new MenuItem(menuTest.Text);
m.Tag = menuTest;
m.Click += new EventHandler(m_Click);
mi.MenuItems.Add(m);
}
this.Menu = menu;
在Menu的Click事件中我们就根据保存起来的Tag属性的MenuTest 对象来动态的创建实例以及调用Run方法
private void m_Click(object sender, EventArgs e)
{
MenuItem m = sender as MenuItem;
MenuTest mt = m.Tag as MenuTest;
Assembly assembly = Assembly.LoadFrom(mt.ActionDll);
object obj = assembly.CreateInstance(
mt.ActionType,
true,
BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public,
null,
null,
null,
null);
Type type = obj.GetType();
MethodInfo mi = type.GetMethod("Run");
mi.Invoke(obj, null);
}
好了,这个例子基本上就结束了,在这个例子中需要注意的地方是:
1、BindingFlags的作用,具体的定义请参考MSDN(http://msdn.microsoft.com/en-us/library/system.reflection.bindingflags.aspx)
2、假设你的Run方法需要接收参数或者有不同的重载,那么你在GetMethod的时候需要把参数的类型传进去,也就是调用type.GetMethod(sting name,Type[] types)这个重载
3、在我这个例子中,XML和DLL文件都是和Form所在的EXE放在一个目录下的
下面我们再举一个例子,这个问题是曾经一个网友提问过的。
假设我们有个按钮,如何获得这个按钮的Click事件所挂的所有的方法
比如我们有个按钮叫做btn,加载它的Click事件
this.btn.Click += new EventHandler(btn_Click);
一般我们只加载一个方法,但是也有的时候我们会加载很多方法,比如:
this.btn.Click += new EventHandler(btn1_Click);
this.btn.Click += new EventHandler(btn2_Click);
this.btn.Click += new EventHandler(btn3_Click);
现在我们想获得这个btn的Click事件的所有方法
其实也很简单,主要是利用反射来获得他的委托列表,主要代码如下:
PropertyInfo pi = (typeof(System.Windows.Forms.Button)).GetProperty("Events",
BindingFlags.Instance | BindingFlags.NonPublic);
EventHandlerList ehl = (EventHandlerList)pi.GetValue(btn, null);
FieldInfo fi = (typeof(Control)).GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic);
Delegate d = ehl[fi.GetValue(null)];
if (d != null)
{
System.Delegate[] dels = d.GetInvocationList();
for (int i = 0; i < dels.Length; i++)
{
string s = dels[i].Method.Name;
//d = System.MulticastDelegate.Remove(d, dels[i]);
}
}
//ehl[fi.GetValue(null)] = d;
如果把注释掉的内容去掉,则可以取消btn的Click事件的所有方法,当然你也可以根据你的需要来取消特定的方法
好了,关于反射的应用就说这么多吧,反射是比较有用的东西,但是不能过度的使用,否则多多少少的会影响到效率
相关文章推荐
- 反射在.NET中的简单应用(二)
- 反射的简单应用
- .Net中的Hashtable简单介绍和应用 (转Eric.liu's Tech Space)
- C#反射简单应用
- .Net中通过反射技术的应用----插件程序的开发入门
- .Net开发笔记(二十一) 反射在.net中的应用
- .net中的WMI编程(一):WMI介绍及简单应用
- .Net反射技术应用解决对象不同版本方法不同参数的问题
- C#反射的Assembly的简单应用
- .net(c#)随机数的最简单应用
- java反射之Constructor简单应用
- Android反射简单应用
- .net 泛型简单应用
- java反射的简单应用
- 关于DataRow和DataColumn的一点个人简单理解-.NET教程,数据库应用
- .net反射技术的应用—如何调用Java的COM接口
- 友好显示维护中 .net web 应用的简单方法
- .net中使用反射的简单例子
- 【设计模式】工厂模式结合反射技术的简单应用