您的位置:首页 > 其它

反射在.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事件的所有方法,当然你也可以根据你的需要来取消特定的方法

好了,关于反射的应用就说这么多吧,反射是比较有用的东西,但是不能过度的使用,否则多多少少的会影响到效率
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: