使用反射

 

                                                                2009-2-17 下午

程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。而其中最直接的应用包括两种:一是获取程序集的结构;一是使用程序集成员(个人认为)。下面,我以两个例子来演示这两个功能的实现。

一、获取程序集的结构

程序集是一个树形结构,下面这个例子叫“程序集查看器”,这是一个窗体程序的例子。

本程序功能:用于将任何的程序集文件(*.dll*.pdf*.exe)的结构的查看。

实现原理:

首先根据选择的程序集全名(包括目录和文件名)定义一个Assembly对象的实例,然后调用此对象的GetTypes()方法获取此对象下的一级子类型,接着对各个子类型的各字段、属性、方法和事件进行遍历、显示。

在此说明一下“BindingFlags”。 Bindingflags”是一个枚举类型,用来指定控制绑定和由反射执行的成员和类型搜索方法的标志。比如其中的“BindingFlags.Static”在这里的作用是遍历范围,包含这定义为“Static”的成员。

         另外,为了非常直观地显示程序集的结构,我选择了TreeView控件。

         当然,此示例程序还有许多需求完善和改进的地方,比如,对程序集的显示时,没有把访问域显示出来,所以,我们还不能从显示的结果中看出此成员是“public”的,还是“private”的。另外,我们还可以加入对应成员的IL代码块显示和导出功能。

         好,现在,我就把整个步骤和代码列出如下。

1.       打开Visual Studio2008,依次选择“新建”->项目,在打开的对话框中,展开Visual C#,选择Windows,在右侧选择“Windows窗体应用程序”,项目名称设置为“Reflection”。单击确定,建立一个新的窗体项目。

2.       将自动建立的窗体“Form1”的Text属性设置为“程序集查看器”,然后将窗体设置为适当大小。

3.       从工具箱中,向窗体中拖入一个SplitContainer控件,将其Dock属性设置为:Fill,将Orientation属性设置为:Horizontal

4.       SplitContainer的上面的Panel中拖入一个按钮,其Text属性设置为:“选择程序集文件(&O)”。此按钮的作用是,打开一个选择文件对话框,用于选择需要查看的程序集文件。

5.       在按钮后,拖入一个Label控件,将其Text值清空。

6.       从属性上的下拉列表框中选择SplitContainer控件(如下图所示),并在窗口中拖动它的Panel间隔线,使两个Panel的大小适当。

7.       SplitContainer的下面的Panel中加入一个TreeView控件,并将其Dock属性设置为:Fill

 

8.       展开工具箱中的“对话框”控件组,双击OpenFileDialog控件,添加一个OpenFileDialog控件。在属性面板中,将其Filter属性设置为:“所有文件|*.*|dll文件|*.dll|exe文件|*.exe”。

至此,窗口的界面设计完成。其界面如下图所示。

2009021714355157.jpg2009021714361060.jpg

9.       现在给程序添加代码。双击按钮,在其事件中,添加如下代码:

  DotNet 编写的 Dll exe 文件。
if  (openFileDialog1.ShowDialog()  ==  DialogResult.OK)

            {

                treeView1.Nodes.Clear();

                Assembly a 
=  Assembly.LoadFile(openFileDialog1.FileName);

                label1.Text 
=   " 程序集全局信息: "   +  a.FullName;

                Type[] arr 
=  a.GetTypes();

 

                BindingFlags flags 
=  (BindingFlags.NonPublic  |  BindingFlags.Public  |

            BindingFlags.Static 
|  BindingFlags.Instance  |  BindingFlags.DeclaredOnly);

 

                
foreach  (Type t  in  arr)

                {

                    TreeNode node 
=   new  TreeNode();

                    node.Text 
=  t.FullName;

 

                    FieldInfo[] arrF 
=  t.GetFields(flags);

                    
foreach  (FieldInfo f  in  arrF)

                    {

                        node.Nodes.Add(
" 字段: "   +  f.FieldType  +   "   "   +  f.Name);

                    }

 

                    PropertyInfo[] arrP 
=  t.GetProperties(flags);

                    
foreach  (PropertyInfo p  in  arrP)

                    {

                        node.Nodes.Add(
" 属性: "   +  p.PropertyType  +   "   "   +  p.Name);

 

                    }

 

                    MethodInfo[] arrM 
=  t.GetMethods(flags);

                    
foreach  (MethodInfo m  in  arrM)

                    {

                        
string  mString  =   string .Format( " 方法:{0} {1}(|||) " , m.ReturnType, m.Name),

                            pString 
=   "" ;

                        ParameterInfo[] pi 
=  m.GetParameters();

                        
foreach  (ParameterInfo p  in  pi)

                        {

                            pString 
+=  p.ParameterType  +   "   "   +  p.Name  +   "   " ;

                        }

                        mString 
=  mString.Replace( " ||| " , pString);

 

                        node.Nodes.Add(mString);

                    }

 

                    EventInfo[] arrE 
=  t.GetEvents(flags);

                    
foreach  (EventInfo ei  in  arrE)

                    {

                        
string  eString  =   string .Format( " 事件:{0} " , ei.Name);

 

                        node.Nodes.Add(eString);

                    }

 

                    treeView1.Nodes.Add(node);

                }

            }

 

至此,本示例程序完成。可以把本程序作为一个小工具来使用,用它来查一下某个程序集的结构,非常简单,便于我们使用他人使用

按下F5运行此程序,单击按钮,打开“选择文件对话框”,选择一个程序集文件,如选择本程序生成的Reflection.exe,得到结果,如下图所示:

 

2009021714364247.jpg 

二、使用程序集成员

程序集成员包括很多种类型,如字段、方法、事件。这里,我仅以调用程序集中的方法为例来演示使用程序集成员的一般方法。

说到调用方法,有人问:我们不使用反射也可以调用程序集元数据中的方法呀!我可以对相关的dllexe文件引用进项目,然后不就可以调用其中的方法了吗?

是的,一般情况下,使用“引用”来使用其中的方法是可以的,不过使用反射,有一定优势的。比如说,一般情况下,我们只通过“引用”的方法,是无法使用程序集中的私有方法的,而只能使用已经公开的方法或其他成员(据我目前的使用经验是这样的,高手们有不同见解,敬请指教)。可以使用反射,就可以使用程序集中所有你需要的成员。

本例原理:首先是根据用户输入的程序集路径建立一个Assemply对象,然后,获取方法所在的类的类型。而后创建两个MethodInfo对象,用于存放获取的两个方法。

另外,为了调用程序集中的私有方法,本例同样使用了BindingFlags枚举。

再次说明一下,为了测试方便和易于理解,本例所调用的程序集就是本例生成的exe文件,所调用的程序集路径和调用的方法,我已经写到代码中了。如果你想把此例变得通用,可以让程序接受输入的路径和调用的方法的名称。

代码的其他说明,我已经写到注释中了,大家有什么别的问题,可以在此提问。

我测试的运行结果如下图所示:

 

2009021714371248.jpg

现给出本例代码如下:

using  System;

using  System.Reflection;

 

namespace  InvokeMethod

{

    
///   <summary>

    
///  本例通过反射实现了对数据库集文件(.dll或.exe形式)中的方法的调用

    
///   </summary>

    
class  Program

    {

        
static   void  Main( string [] args)

        {

            Assembly a 
=  Assembly.LoadFile( @" E:\developingApp\Reflection\InvokeMethod\bin\Debug\InvokeMethod.exe " );

            
// Console.WriteLine(a.FullName);

 

            BindingFlags flags 
=  (BindingFlags.NonPublic  |  BindingFlags.Public  |

                BindingFlags.Static 
|  BindingFlags.Instance  |  BindingFlags.DeclaredOnly);

 

            Type t 
=  a.GetType( " InvokeMethod.Program " );

 

            MethodInfo mi 
=  t.GetMethod( " GetString " , flags), // 获取private方法"GetString"

                mi2 
=  t.GetMethod( " GetHello " ); // 获取public方法"GetHello"

            
object  obj  =  a.CreateInstance( " InvokeMethod.Program " );

 

            Console.WriteLine(mi.Invoke(obj, 
null )); // 调用private方法"GetString"

            Console.WriteLine(mi2.Invoke(obj, 
new   string [ 1 ] {  " ChuJian "  })); // 调用public方法"GetHello"

 

            Console.ReadKey();

        }

        
static   private   string  GetString()

        {

            
return   " Some String From Assembly. " ;

        }

        
public   string  GetHello( string  name)

        {

            
return   string .Format( " Hello {0}! " , name);

        }

 

    }

}

转载于:https://www.cnblogs.com/chujian/archive/2009/02/17/1392448.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值