反射由浅入深了解学习(一)

 

一,反射三个步骤
1, 加载dll获取的程序集
2,通过加载的dll得到的程序集和类型的全名,得到想要的类型
3,使用指定类型的默认构造函数来创建该类型的实例

二,代码结构如下图

二,Program.cs代码如下:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ReflectionDemo
{
    class Program
    {

        private static string config = ConfigurationManager.AppSettings["DbConfig"]; //反射的配置
        static void Main(string[] args)
        {
            Assembly assembly = Assembly.Load(config.Split(',')[1]); //加载dll获取的程序集
            Type type = assembly.GetType(config.Split(',')[0]); //通过加载的dll得到的程序集和类型的全名,得到想要的类型
            //显示加载程序集的路径
            foreach (Module item in assembly.GetModules())
            {
                Console.WriteLine("DLL地址{0}", item.FullyQualifiedName);
            }
            ///显示加载程序集的名称
            foreach (Type item in assembly.GetTypes())
            {
                Console.WriteLine("DLL名称{0}", item.FullName);
            }
            ///显示所有方法
            foreach (MethodInfo item in type.GetMethods())
            {
                Console.WriteLine("方法名称{0}", item.Name);
            }

            //创建对象,使用指定类型的默认构造函数来创建该类型的实例
            object oDbHelper = Activator.CreateInstance(type);

            ///反射调用无参数方法
            ///PS修改BLL库需要拷贝到当前的控制台程序
            MethodInfo query1 = type.GetMethod("Query");
            query1.Invoke(oDbHelper, null);

            //发现不明确匹配,因为Query1方法重载了,跟MVC中的找视图和方法时报错一样,多个请求路由存在多个相同命名视图逻辑一样报错
            //MethodInfo query8 = type.GetMethod("Query1");
            //query8.Invoke(oDbHelper, new object[] { "string参数" });

            ///反射带参数方法
            MethodInfo query2 = type.GetMethod("Query1", new Type[] { typeof(string) });
            query2.Invoke(oDbHelper, new object[] { "string参数" });

            MethodInfo query3 = type.GetMethod("Query1", new Type[] { typeof(int) });
            query3.Invoke(oDbHelper, new object[] { 111 });

            /// PS:对私有方法和静态实例不建议用反射来获取实现,破坏了设计的原则,但是测试和观看源码时可以使用
            //私有方法的反射
            MethodInfo query4 = type.GetMethod("QueryPrivate", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            query4.Invoke(oDbHelper, null);

            //私有带参数方法的反射
            MethodInfo query5 = type.GetMethod("QueryPrivateParam", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(int) }, null);
            query5.Invoke(oDbHelper, new object[] { 444 });

            MethodInfo query6 = type.GetMethod("QueryPrivateParam", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null);
            query6.Invoke(oDbHelper, new object[] { "string参数" });

        //对单例模式创建实例
        //Type Singleton = assembly.GetType("BLLExt.Singleton");
        ////object ob = Activator.CreateInstance(Singleton); //报错:没有为该对象定义无参数的构造函数
        //object ob = Activator.CreateInstance(Singleton,true);


            Console.ReadKey();
        }
    }
}

SqlHelper.cs代码如下:

using IBLL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BLL
{
    public class SqlHelper: IDbHelper
    {
        public SqlHelper()
        {
            Console.WriteLine("{0}被构造", this.GetType().Name);
        }


        public void Query()
        {
            Console.WriteLine("{0}.Query", this.GetType().Name);
        }
        public void Query1(string obj)
        {
            Console.WriteLine("{0}---{1}.Query", obj, this.GetType().Name);
        }
        public void Query1(int obj)
        {
            Console.WriteLine("{0}---{1}.Query", obj, this.GetType().Name);
        }
        private void QueryPrivate()
        {
            Console.WriteLine("{0}.QueryPrivate", this.GetType().Name);
        }
        private void QueryPrivateParam(string obj)
        {
            Console.WriteLine("{0}---{1}.QueryPrivateParam", obj, this.GetType().Name);
        }
        private void QueryPrivateParam(int obj)
        {
            Console.WriteLine("{0}---{1}.QueryPrivateParam", obj, this.GetType().Name);
        }
    }
}

IDbHelper.cs

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

namespace IBLL
{
    public interface IDbHelper
    {
         void Query();
    }
}

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="DbConfig" value="BLL.SqlHelper,BLL"/>
    <!--<add key="DbConfig" value="BLLExt.MySqlHelper,BLLExt"/>-->
  </appSettings>
</configuration>

 三,如上代码,我们需要注意的是:

1,创建反射的步骤
2,反射调用无参数方法和有参方法的区别
3,重载方法的反射需标明参数的类型,如下:

//发现不明确匹配,因为Query1方法重载了,跟MVC中的找视图和方法时报错一样,多个请求路由存在多个相同命名视图逻辑一样报错
MethodInfo query8 = type.GetMethod("Query1");
query8.Invoke(oDbHelper, new object[] { "string参数" });

以上报错,重载方法无参数正确写法

//重载方法无参数反射的使用
MethodInfo query9 = type.GetMethod("Query1", new Type[] { });
query9.Invoke(oDbHelper, null);

4,对私有方法的反射

四,反射的扩展

1,对单例的反射

 Singleton.cs

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

namespace BLL
{
    public class Singleton
    {
        public static Singleton _Instance = new Singleton();
        private Singleton() {
            Console.WriteLine("{0}被构造了",this.GetType().Name);
        }
    }
}

反射代码

//对单例模式创建实例
Type Singleton = assembly.GetType("BLLExt.Singleton");
 ////object ob = Activator.CreateInstance(Singleton); //报错:没有为该对象定义无参数的构造函数
object ob = Activator.CreateInstance(Singleton,true);

 2,反射类库的切换,通过反射获取的实例都是不需要引用的,如下图,没有引用bll

那我们怎么动态切换库呢?再用反射时只需要更改配置文件App.config即可,如配置

更改配置为,BLLExt.MySqlHelper,输出结果是不一样的

PS :但是每次我们修改BLL和BLLExt库时都要将其生成的DLL手动拷贝到ReflectionDemo的bin文件下,原因是:ReflectionDemo没有引用这两个库,重新生成不会生成到改目录的bin目录下

反射由浅入深了解学习(二)

 

posted @ 2019-05-15 11:22  叶丶梓轩  阅读(338)  评论(0编辑  收藏  举报