我是靠谱客的博主 忧虑月饼,最近开发中收集的这篇文章主要介绍反射在.NET中的简单应用(一),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

反射在.NET的应用很广泛,我们可以利用反射动态加载程序集,动态的创建类型的实例,或从现有对象获取类型并调用其方法或访问其字段和属性。有关反射的更多信息请参考MSDN(http://msdn.microsoft.com/zh-cn/library/ms173183(VS.80).aspx)

下面我们举两个例子来简单的说明下在.NET中如何应用反射。

假设我们有个系统可以动态扩展其功能,我们可以采用如下方法实现。

我们有个配置文件,叫做Config.xml,格式如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Root>
  3.   <MenuTests>
  4.     <Menu Text="" ActionDll="" ActionType="" />
  5.     <Menu Text="" ActionDll="" ActionType="" />
  6.   </MenuTests>
  7. </Root>

有个Form,通过加载这个XML文件来生成他的菜单

 

 

 

Menu节点的Text属性就是将来菜单显示的Text

ActionDll是点击菜单时调用的类的所在的DLL

ActionType是点击菜单时调用的类的全称(命名空间+类名)

通过这个XML文件,我们可以动态的加载后续开发的程序

加载这个XML文件,我们可以采用序列化的办法,当然你也可以采用其他办法

这时我们需要建两个辅助类,代码如下:

 

这个基类可以是一个abstract的,包含一个abstract的方法,代码如下:

  1. public abstract class ReflecteAbstractBase
  2. {
  3.     public ReflecteAbstractBase()
  4.     {
  5.     }
  6.     public abstract void Run();
  7. }

这个基类只有一个构造函数和一个方法,继承他的类都要重写这个Run方法,然后我们在程序中利用反射去调用这个方法就可以了,当然可以根据你的需要在添加些其他的方法以及属性

假设我们后续开发的功能叫做RelecteTestProject,那么我们可以写下如下代码:

 

 

  1. namespace RelecteTestApp
  2. {
  3.     public class RelecteTestProject : ReflecteAbstractBase
  4.     {
  5.         public RelecteTestProject() : base()
  6.         {
  7.         }
  8.         public override void Run()
  9.         {
  10.             //这里是程序的入口,在这里可以添加你需要的代码
  11.         }
  12.     }
  13. }

同时我们去修改那个配置文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Root>
  3.   <MenuTests>
  4.     <Menu Text="RelecteTestProject" 
  5.         ActionDll="RelecteTestProject.dll"  
  6.         ActionType="RelecteTestApp.RelecteTestProject" />
  7.   </MenuTests>
  8. </Root>

好了,我们准备工作都做好了,下面来看看如何加载这个XML文件,并且动态的调用它的方法

 

 

在需要加载菜单的Form中,我们可以采用如下代码来实现菜单的加载:

  1. XmlSerializer mySerializer = new XmlSerializer(typeof(MenuTestCollection));
  2. FileStream myFileStream = new FileStream("Config.xml", FileMode.Open);
  3. MenuTestCollection config = (MenuTestCollection)mySerializer.Deserialize(myFileStream);
  4. myFileStream.Close();
  5. MainMenu menu = new MainMenu();
  6. menu.Name = "menu";
  7. MenuItem mi = new MenuItem("test");
  8. menu.MenuItems.Add(mi);            
  9. foreach (MenuTest menuTest in config.MenuTests)
  10. {
  11.     MenuItem m = new MenuItem(menuTest.Text);
  12.     m.Tag = menuTest;
  13.     m.Click += new EventHandler(m_Click);
  14.     mi.MenuItems.Add(m);
  15. }
  16. this.Menu = menu;

在Menu的Click事件中我们就根据保存起来的Tag属性的MenuTest 对象来动态的创建实例以及调用Run方法

  1. private void m_Click(object sender, EventArgs e)
  2. {
  3.     MenuItem m = sender as MenuItem;
  4.     MenuTest mt = m.Tag as MenuTest;
  5.     Assembly assembly = Assembly.LoadFrom(mt.ActionDll);
  6.     object obj = assembly.CreateInstance(
  7.                     mt.ActionType,
  8.                     true,
  9.                     BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public,
  10.                     null,
  11.                     null,
  12.                     null,
  13.                     null);
  14.     Type type = obj.GetType(); 
  15.     MethodInfo mi = type.GetMethod("Run");
  16.     mi.Invoke(obj, null);
  17. }

好了,这个例子基本上就结束了,在这个例子中需要注意的地方是:

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事件的所有方法

其实也很简单,主要是利用反射来获得他的委托列表,主要代码如下:

  1. PropertyInfo pi = (typeof(System.Windows.Forms.Button)).GetProperty("Events"
  2.                 BindingFlags.Instance | BindingFlags.NonPublic);
  3. EventHandlerList ehl = (EventHandlerList)pi.GetValue(btn, null);
  4. FieldInfo fi = (typeof(Control)).GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic);
  5. Delegate d = ehl[fi.GetValue(null)];
  6. if (d != null)
  7. {
  8.     System.Delegate[] dels = d.GetInvocationList();
  9.     for (int i = 0; i < dels.Length; i++)
  10.     {
  11.         string s = dels[i].Method.Name;
  12.         //d = System.MulticastDelegate.Remove(d, dels[i]);
  13.     } 
  14. }
  15. //ehl[fi.GetValue(null)] = d;

如果把注释掉的内容去掉,则可以取消btn的Click事件的所有方法,当然你也可以根据你的需要来取消特定的方法

 

好了,关于反射的应用就说这么多吧,反射是比较有用的东西,但是不能过度的使用,否则多多少少的会影响到效率

 

 

 

最后

以上就是忧虑月饼为你收集整理的反射在.NET中的简单应用(一)的全部内容,希望文章能够帮你解决反射在.NET中的简单应用(一)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部