.net的反射机制

学习4点:

1.反射有什么用,什么情况下用反射。                  (参考资料http://dotnet.9sssd.com/csbase/art/733)

2.通过简单的例子理解反射的运用。                     (参考资料http://www.2cto.com/kf/201110/109636.html)

3.通过复杂的例子理解更多反射的用法,语法。(参考资料ttp://blog.163.com/shensc@126/blog/static/13128965220106183155664/)

4.反射的性能优化。                                                 (参考资料http://www.soaspx.com/dotnet/asp.net/tech/tech_20120407_8898.html)


1.反射有什么用,什么情况下用反射。  


反射机制就是你给它一个类或者程序集,它就能知道这个类或者程序集中有什么方法和类型属性,然后模拟出这个类中的方法和类型属性。


这样我们就可以很灵活动态的创建需要的类,调用相应的方法。


一般我们遇到多个类似的功能实现用同一个接口时但还不能确定是用哪一个实现时就可以用反射作出相应的判断。


在抽象工厂模式中经常用反射,典型的例子是数据读取层。

一个项目可能用到SqlSever,Access,Orace或者Txt,XML来当存取数据,他们的方法都是统一,比如增,删,修,读等。

这个时候就是定义一个IDataAccess接口,这个接口定义了统一的方法,增,删,修,读等,然后分别用不同的实现类来继承这个接口,比如SqlServer类,XmL类,定义为SqlServerDataAccess,XMLDataAccess,他们都继承IDataAccess。

在应用的时候项目可以通过简单的修改或者配置来使用Sqlserver或者XML数据库,这个时候就可以使用反射来决定接口IDataAccess到底使用哪个实现类。

抽象工厂模式中使用配置文件来设置使用Sqlserver还是XML数据实现类。在配置文件中定义“程序集和命名空间类名”的信息,这样通过修改配置文件就可以决定使用Sqlserver还是XML数据实现类。


2.通过简单的例子理解反射的运用。

首先,我新建一个普通的类库项目。在该项目的测试类中,定义好 属性、静态方法、实例方法、无参方法等... 

.net的反射机制_第1张图片


代码如下:

using System; 

using System.Collections.Generic; 

using System.Linq; 

using System.Text;  

namespace ReflectorTest 

{ 

    class Test 

    { 

        private string name; 

        public string Name { get; set; } 

        /// <summary> 

        /// 静态方法 

        /// </summary> 

        /// <returns></returns> 

        public static string staticMethod(string  name) 

        { 

            return name+"这是一个静态方法"; 

        } 

        /// <summary> 

        /// 实例方法 

        /// </summary> 

        /// <param name="name"></param> 

        /// <returns></returns> 

        public string sayHello(string name)  

        { 

            return "你好:" + name+"我是一个有参的方法"; 

        } 

        /// <summary> 

        /// 无参的方法 

        /// </summary> 

        /// <returns></returns> 

        public string noParm()  

        { 

            return "我是一个无参方法"; 

        } 

    } 

} 


然后在解决方案里添加一个窗口

.net的反射机制_第2张图片

.net的反射机制_第3张图片




拉入两个按钮 每个按钮执行一个反射函数:reflectorDemo()执行类库中的函数, reflectorInfo()遍历出类库中所有的方法,属性,类型

.net的反射机制_第4张图片


代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using ReflectorTest;


namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            reflectorDemo(); 
        }


        private void button2_Click(object sender, EventArgs e)
        {
            reflectorInfo(); 
        }




         public static void reflectorDemo()  
        { 


            Assembly ass; 
            Type type; 
            MethodInfo method; 
           try 
            {
                ass = Assembly.Load("ReflectorTest"); //根据命名空间加载
                //ass = Assembly.LoadFile("ReflectorTest.DLL");根据文件名称尝试加载 
                type = ass.GetType("ReflectorTest.Test");//根据类型名称,反射出该类型(注意格式是:“命名空间.类名”) 
                object o =Activator.CreateInstance(type);//创建该类型的对象实例 
               
               method=type.GetMethod("sayHello");//反射获取方法(实例方法) 
               string s = (string)method.Invoke(o,new string[] {"张三"});//调用实例方法 
               MessageBox.Show("调用实例方法返回:" + s); 

                method=type.GetMethod("noParm");//无参方法 
                s= (string) method.Invoke(o,null);//调用无参函数 
                MessageBox.Show("调用无参方法返回:" + s);  


                //type.GetProperties()//获取该类型下面的所有公共属性            

               method=type.GetMethod("staticMethod");//静态函数 
                s = (string)method.Invoke(null, new string[] { "张三" });//调用静态方法 
               MessageBox.Show("调用静态方法返回:"+s); 

               //根据指定的属性名称,获得属性值 
               type.GetProperty("Name").GetValue(o,null); 
                //给属性设值 
                type.GetProperty("Name").SetValue(o, "张三", null); 


            } 
            catch (Exception) 
            { 
                throw; 
            } 
            finally 
            { 
                  ass=null; 
                type=null; 
                method=null;            
            }         
        } 
        /// <summary> 
        /// 利用反射获取程序集中类,类的成员(方法,属性等) 
        /// </summary> 
        public static void reflectorInfo()  
        {
            Assembly ass = Assembly.Load("ReflectorTest");
          //  Assembly ass = Assembly.LoadFrom("ReflectorTest.DLL");加载程序集 

            Module[] modules = ass.GetModules();//模块信息   
            Type[] types = ass.GetTypes();//获取该程序集所包含的所有类型 
            foreach (var item in types) 
            { 
                MessageBox.Show("所包含的类型类型名称:" + item.Name); 
                MethodInfo[] methods = item.GetMethods();//获取该类型下所包含的方法信息 
                foreach (var method in methods)  
                {
                    MessageBox.Show("该类下所包含的方法名称:" + method.Name); 
          } 
                PropertyInfo[] PropertyInfo = item.GetProperties(); 
                foreach (var pro in PropertyInfo) 
                {
                    MessageBox.Show("该类下所包含的属性名称:" + pro.Name); 
                } 
            } 
        } 
    } 
}


把窗口设置为启动项


.net的反射机制_第5张图片


并对窗体添加 ReflectorTest类库的关联


.net的反射机制_第6张图片

.net的反射机制_第7张图片




否则useing  ReflectorTest  会报找不到。

.net的反射机制_第8张图片



 F5热键 测试结果:

点击


结果:

.net的反射机制_第9张图片

.net的反射机制_第10张图片

.net的反射机制_第11张图片


发现实现了程序集中的方法。

但我们并没有(直接)调用程序集中的函数,这就是反射的作用。模拟出程序集中的函数实现。


点击



结果:

.net的反射机制_第12张图片

.net的反射机制_第13张图片

。。。。等等 

遍历了程序集中的所有方法和属性。也就是说通过反射我们能知道程序集里有什么方法函数和属性。



3.通过复杂的例子理解更多反射的用法,语法


解决方案构造方法与简单例子类似。

直接上代码,以后用到相关语法的时候可以学习着写:


类库中的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Models
{
    public class User
    {
        /// <summary>
        /// 字段
        /// </summary>
        public string Field;

        private int age;
        /// <summary>
        /// 属性:年龄
        /// </summary>
        public int Age
        {
            get { return age; }
            set { age = value; }
        }

        private string name;
        /// <summary>
        /// 属性:名称
        /// </summary>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// 无参数构造函数
        /// </summary>
        public User()
        {
            this.name = "调用了无参数的构造函数";
        }

        /// <summary>
        /// 带参构造函数
        /// </summary>
        public User(string name)
        {
            this.Name = name;
           // this.Age = age;
        }

        /// <summary>
        /// public方法  
        /// </summary>
        public string PublicClassMethod()
        {
            return string.Format("您反射了一个Public方法");
        }

        /// <summary>
        /// private方法
        /// </summary>
        private string PrivateClassMethod()
        {
            return string.Format("您反射了一个Private方法");
        }

        /// <summary>
        /// static方法
        /// </summary>
        public static string StaticMethod()
        {
            return "您反射了一个Static方法";
        }

        /// <summary>
        /// 无带参方法
        /// </summary>
        public string Show1()
        {
            return string.Format("我的名字叫:{0},今年{1}岁了!", this.Name, this.Age);
        }

        /// <summary>
        /// 带参方法
        /// </summary>
        public string Show(string aihao)
        {
            return string.Format("大家好,我的爱好是:{0}!", aihao);
        }

        /// <summary>
        /// 自定义事件类型
        /// </summary>
        public event EventHandler eventHandler;

        /// <summary>
        /// 处理事件
        /// </summary>
        public void DoEvent()
        {
            eventHandler(null, EventArgs.Empty);
        }
    }
}



窗体的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using Models;

namespace test
{
    public partial class Form3 : Form
    {
        public Form3()
        {
            InitializeComponent();
        }

        private void Form3_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (DialogResult.OK != MessageBox.Show("你确定要退出系统", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information))
            {
                e.Cancel = true;
                //  MessageBox.Show(e.CloseReason.ToString());
            }
            else
            {

            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            //获取程序集 
            Assembly assembly = Assembly.Load("Models");
            Assembly assembly2 = Assembly.LoadFrom("Models.dll");

            //从程序集中获取指定对象类型;
            Type type = assembly2.GetType("Models.User");

            //使用Activator创建一个实例使用Activator创建一个实例
            User user2 = Activator.CreateInstance(type) as User;
            //通过对象类型创建对象实例  
            User user = assembly.CreateInstance("Models.User") as User;

            // 调用无参构造
            ConstructorInfo studentConstructor = type.GetConstructor(new Type[] { });
            User user3 = studentConstructor.Invoke(new object[] { }) as User;

            //调用有参构造 
            ConstructorInfo studentConstructor2 = type.GetConstructor(new Type[] { typeof(string) });
            User user4 = studentConstructor.Invoke(new object[] { "您调用了有参构造创建了一个类实例。"}) as User;

            //调用非静态方法
            string returnValue = type.InvokeMember("PublicClassMethod", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, user, new object[] { }) as string;

            // 调用静态方法 .       
            string returnValue2 = type.InvokeMember("StaticMethod", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, user, new object[] { }) as string;

            // 调用私有方法 .       
            string returnValue3 = type.InvokeMember("PrivateClassMethod", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, user, new object[] { }) as string;


            //反射参数反射参数
            MethodInfo parameterMethod = type.GetMethod("Show");

            ParameterInfo[] paras = parameterMethod.GetParameters();
            for (int i = 0; i < paras.Length; i++)
            {
                MessageBox.Show(string.Format("参数名称:{0},参数类型:{1},是否可选:{2},位置:{3},默认值:{4}", paras[i].Name, paras[i].ParameterType.ToString(), paras[i].IsOptional.ToString(), paras[i].Position.ToString(), paras[i].DefaultValue.ToString()));

                //反射属性反射属性
                type.InvokeMember("Name", BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance, null, user, new object[] { "您反射了一个属性" });
                string returnValue4 = type.InvokeMember("Name", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance, null, user, new object[] { }) as string;

                //反射字段反射字段
                type.InvokeMember("Field", BindingFlags.SetField | BindingFlags.Public | BindingFlags.Instance, null, user, new object[] { "您反射了一个字段" });
                string returnValue5 = type.InvokeMember("Field", BindingFlags.GetField | BindingFlags.Public | BindingFlags.Instance, null, user, new object[] { }) as string;
            }
        }
    }
}

BindingFlags用于指定你要得的的函数或者成员的类

BindingFlags.InvokeMethod指调用方法。

BindingFlags.SetProperty指设置属性

BindingFlags.GetProperty指得到属性

BindingFlags.SetField指设置字段

BindingFlags.GetField指得到字段

BindingFlags.Instance 或 BindingFlags.Static必须指定其一,以确定你要的是否是静态方法. 
BindingFlags.Instance ,反射的时候会去实例成员,也就是非静态的,你的方法是非静态的,就必须必须加上这个才行。
BindingFlags.Static ,要反射静态的方法就必须加上这个。


4.反射的性能优化。


我们用2.简单例子中的reflectorDemo()函数来学一下怎么优化。

  public static void reflectorDemo()  
        { 


            Assembly ass; 
            Type type; 
            MethodInfo method; 
           try 
            {
                ass = Assembly.Load("ReflectorTest"); //根据命名空间加载
                //ass = Assembly.LoadFile("ReflectorTest.DLL");根据文件名称尝试加载 
                type = ass.GetType("ReflectorTest.Test");//根据类型名称,反射出该类型(注意格式是:“命名空间.类名”) 
                object o =Activator.CreateInstance(type);//创建该类型的对象实例 
               
               method=type.GetMethod("sayHello");//反射获取方法(实例方法) 
               string s = (string)method.Invoke(o,new string[] {"张三"});//调用实例方法 
               MessageBox.Show("调用实例方法返回:" + s); 

                method=type.GetMethod("noParm");//无参方法 
                s= (string) method.Invoke(o,null);//调用无参函数 
                MessageBox.Show("调用无参方法返回:" + s);  


                //type.GetProperties()//获取该类型下面的所有公共属性            

               method=type.GetMethod("staticMethod");//静态函数 
                s = (string)method.Invoke(null, new string[] { "张三" });//调用静态方法 
               MessageBox.Show("调用静态方法返回:"+s); 

               //根据指定的属性名称,获得属性值 
               type.GetProperty("Name").GetValue(o,null); 
                //给属性设值 
                type.GetProperty("Name").SetValue(o, "张三", null); 


            } 
            catch (Exception) 
            { 
                throw; 
            } 
            finally 
            { 
                  ass=null; 
                type=null; 
                method=null;            
            }         
        } 


比如:优化调用实例方法:

原反射:

 type = ass.GetType("ReflectorTest.Test");//根据类型名称,反射出该类型(注意格式是:“命名空间.类名”) 
                object o =Activator.CreateInstance(type);//创建该类型的对象实例 
               
               method=type.GetMethod("sayHello");//反射获取方法(实例方法) 
               string s = (string)method.Invoke(o,new string[] {"张三"});//调用实例方法 
               MessageBox.Show("调用实例方法返回:" + s); 

通过委托优化:


 public delegate int AddMethod(string a); // 委托
type = ass.GetType("ReflectorTest.Test");//根据类型名称,反射出该类型(注意格式是:“命名空间.类名”)             
 object o =Activator.CreateInstance(type);//创建该类型的对象实例  
method=type.GetMethod("sayHello");//反射获取方法(实例方法) 

  var newMethod = (AddMethod)Delegate.CreateDelegate(typeof(AddMethod), obj, method);
  
string s = newMethod(new string[] {"张三"});//调用实例方法 
         MessageBox.Show("调用实例方法返回:" + s); 


上面的代码看起来多了几行,而且还需要自定义一个委托,写起来挺麻烦的。因此我们的测试代码里面还实现了另外一种形式,其实它也是委托:
var newMethod = (Func<TestObject, string>)Delegate.CreateDelegate(typeof(Func<TestObject, string>), method);


通过.NET4动态编程的实现

 dynamic obj = new Test();

 // 有木有发现这个代码超级简单? Test对应程序集中的类名。
      
string s =obj.sayHello(“张三”);
MessageBox.Show("调用实例方法返回:" + s);


   

你可能感兴趣的:(.net的反射机制)