.NET反射学习总结1

程序运行图解:

理解反射之前,先理解下程序的执行过程,如下图所示:

程序员写了高级语言(c#、vb等等),经过编译器编译后,生成DLL或者EXE文件,文件经过JIT编译成机器码,最终被计算机执行。

如果再细分的话,DLL/EXE文件中包含了元数据和中间语言,中间语言经过JIT编译成机器码。

元数据可以理解为数据清单,当CLR执行DLL/EXE时,先去查找元数据,元数据中描述了DLL/EXE的详细信息,比如包含了哪些命名空间,命名空间中有哪些类,类中有哪些方法,有哪些属性。

反射概念:

反射Reflection:System.Reflection,是.Net Framework提供的一个帮助类库,可以读取并使用meatdata(元数据)。

反射初体验:

在.net代码中,如果要加载一个自定义的类库,则需要三部:第一步项目添加类库的引用,第二步是代码中using 类库的命名空间,第三步才是调用类库的方法。

如果要用反射来实现这个步骤,则不需要添加引用的步骤,直接就可以将程序集加载到内存中,并可以读取里面的信息。如下实例所示:

自定义一个接口:

namespace DB.Interface
{
    /// <summary>
    /// 数据访问类
    /// </summary>
    public interface IDBHelper
    {
        void Query();
    }
}

自定义一个MySql的类:

using DB.Interface;
using System;

namespace DB.MySql
{
    public class MySqlHelper : IDBHelper
    {
        public void Query()
        {
            Console.WriteLine("{0}.Query", this.GetType().Name);
        }

        public MySqlHelper()
        {
            Console.WriteLine("{0}被构造", this.GetType().Name);
        }
    }
}

程序的主方法: 

using DB.MySql;
using System;
using System.Reflection;

namespace MyReflection
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("***********************常规用法************************");
                MySqlHelper mySqlHelper = new MySqlHelper();
                mySqlHelper.Query();



                Console.WriteLine("***********************反射用法************************");
                //将dll加载到内存中
                Assembly assembly = Assembly.Load("DB.MySql");//程序集的名称

                foreach (var type in assembly.GetTypes())
                {
                    Console.WriteLine("第一次循环:" + type.Name);

                    foreach (var method in type.GetMethods())
                    {
                        Console.WriteLine(method.Name);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.Read();
        }
    }
}

程序使用常规的写法和反射的写法,分别打印出实例的名称和方法的名称,运行结果如下图:

 都打印出了MySqlHelper这个类名,还有Query方法名。

反射实例中还打印出了ToString等方法名称,其实是Object的方法。

反射用途:

反射的作用不仅是可以查看程序集中内容,它还可以使用程序集,也就是可以调用方法等。

Type type = assembly.GetType("DB.MySql.MySqlHelper");//获取类型
dynamic dDBHelper= Activator.CreateInstance(type);//创建对象
dDBHelper.Query();//调用对象的方法

执行结果如图:

 可以像常规的引用方式一样,调用实例中的方法。

步骤可以分为:1.获取程序集类型 2.创建对象 3.调用对象方法

这样看上去不是很简便,可以对反射的相关方法做一个封装。

using DB.Interface;
using System;
using System.Reflection;
using System.Configuration;

namespace MyReflection
{
    /// <summary>
    /// 定义一个工厂
    /// </summary>
    public class SimpleFactory
    {
        //static关键字表示'静态',它的作用是当程序第一次调用类的时候完成初始化,就执行一次,而且只会执行一次。
        private static string IDBHelperConfig = ConfigurationManager.AppSettings["IDBHelperConfig"];
        private static string DllName = IDBHelperConfig.Split(',')[0];
        private static string TypeName = IDBHelperConfig.Split(',')[1];


        public static IDBHelper CreateInstance()
        {
            Assembly assembly = Assembly.Load(DllName);//程序集的名称
            Type type = assembly.GetType(TypeName);//获取类型
            object oDBHelper = Activator.CreateInstance(type);//创建对象
            IDBHelper iDBHelper = oDBHelper as IDBHelper;
            return iDBHelper;
        }
    }
}

需要在App.config文件中做一个配置:

 <appSettings>
    <add key="IDBHelperConfig" value="DB.MySql,DB.MySql.MySqlHelper"/>
  </appSettings>

 这样做的原因是方便修改引用的程序集名称。

调用的地方就可以这样写:

IDBHelper dBHelper = SimpleFactory.CreateInstance();
dBHelper.Query();

执行结果仍然为:

总结: 

反射的意义在于它是可以动态地加载程序集,实现对程序的扩展。

以上内容都是个人理解,可能有不对或不完整的地方。

猜你喜欢

转载自blog.csdn.net/liangmengbk/article/details/112059074