概述
反射在.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中的简单应用(一)的全部内容,希望文章能够帮你解决反射在.NET中的简单应用(一)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复