.NET 反射原理及其运用

一.何谓反射

反射:是.net framework提供的一个访问metadata的帮助类库,可以获取信息并且使用
动态是反射中的最大优点。

二:反射如何使用

#region 反射的加载方式
获取当前路径下面的dl或者exe,不带后缀(MyReflection.exe 是编译后生成的exe执行文件),从Exe所在的路径进行查找
Assembly assembly = Assembly.Load(@"MyReflection");
//获取完整路径下面的dl或者exe,要加后缀
Assembly assemblyFrom = Assembly.LoadFrom(@"D:\MyReflection\bin\Debug\MyReflection.exe");
//获取完整路径下面的dl或者exe,要加后缀
Assembly assemblyFile = Assembly.LoadFile(@"D:\MyReflection\bin\Debug\MyReflection.exe"); 
foreach (var item in assembly.GetModules())
{
   //Modules当前的exe或者dll的名字(MyReflection.exe)
   Console.WriteLine(item.Name); 
}
//当前所包含的实体类(IDBHelper,SqlServerHelper,Program)
foreach (var item in assembly.GetTypes())
{
     foreach(var method in item.GetMethods()){
          Console.WriteLine(method.Name);      
      }
    Console.WriteLine(item.Name);
}

foreach (var item in assembly.GetCustomAttributes())
{
    Console.WriteLine(item.ToString());
}
//获取到有多个构造函数
foreach (var ctor in type.GetConstructors())
{
Console.WriteLine(ctor.GetParameters());
//获取构造函数里面的参数
foreach (var item in ctor.GetParameters())
{
Console.WriteLine(item.ParameterType);
}
}
#endregion

三.反射的应用

(一)可以利用反射 创建一个类的实例,并调用他的方法

1.创建步骤

例如:

(1).获取类型:
Type dbhelperType = assembly.GetTyp(“Ruanmou.DB.MySql.MySqlHelper”);//== 获取所需创建类型的类型信息,传参数必须传递完整类名,从命名空间开始==
(2).创建类型对应的实例对象
//用Activator.CreateInstance(类型参数)创建所需类型的实例对象
object oDBHelper = Activator.CreateInstance(dbhelperType);
(3).转换并调用方法:
用其对应的接口进行转换
IDBHelper idbhelper = oDBHelper as IDBHelper;
idbhelper.Query();

2.具体应用

在写程序的时候,需要灵活运用类的时候,可以先在配置文件中,将需要的类型配置进去,然后在程序中根据配置文件灵活的创建所需要的类型对象:举例,程序有可能需要多种数据库,MySql 和SqlServer,写底层数据库连接的时候并不知道上层需要哪个,于是可以利用在配置文件中的连接字符串中配置Provider的dll,用反射的方式在底层创建连接字符串的时候,根据上层传入的连接字符串来灵活创建底层连接Connection.

/// <summary>
/// 反射得到一个对象
 /// </summary>
 public class SimpleFactory
 {
     //读取配置文件AppSetting里面的key
     // <appSettings>
     // <add key = "DbConfig" value="MyReflection,MyReflection.MySqlServerHelper"/>
     //</appSettings>
     private static string ConfigStr = ConfigurationManager.AppSettings["DbConfig"];
     private static string DllName = ConfigStr.Split(',')[0];  //命名空间
     private static string TypeName = ConfigStr.Split(',')[1]; //类型要完整命名空间+类名
     public static T CreateInstance<T>()
     {
         Assembly assembly = Assembly.Load(DllName);
         Type type = assembly.GetType(TypeName);
         var objectInstance = Activator.CreateInstance(type);
         return (T)objectInstance; //要强制转换一下,因为牵涉到编译性语言和运行时语言
     }
 }

(二):反射调用多构造函数,调用私有构造函数(破坏单例),调用泛型类

首先创建一个实体类,包含有参无参构造函数,然后有参无参的方法,如下:

/// <summary>
    /// sqlServer
    /// </summary>
    public class SqlServerHelper : IDBHelper
    {
        //private SqlServerHelper()
        //{
        //    Console.WriteLine("私有构造函数");
        //}
        //无参构造函数
        public SqlServerHelper()
        {
            Console.WriteLine("公有无参构造函数");
        }
        //传入一个int型参数的构造函数
        public SqlServerHelper(int iParam)
        {
            Console.WriteLine($"int的构造函数--{iParam}");
        }
        //传入一个string型参数的构造函数
        public SqlServerHelper(string sParam)
        {
            Console.WriteLine($"string的构造函数--{sParam}");
        }
        //传入两个参数的构造函数
        public SqlServerHelper(int iParam, string sParam)
        {
            Console.WriteLine($"int和string的构造函数--int={iParam} ;string={sParam}");
        }
        //类内部的无参方法
    public void Show()
    {
        Console.WriteLine("Show");
    }
    //类内部的Show1的无参方法
    public void Show1()
    {
        Console.WriteLine("Show1的无参方法");
    }
    //类内部的Show1的int重载方法
    public void Show1(int iParam)
    {
        Console.WriteLine($"Show1的int重载--{iParam}");
    }
    //类内部的Show1的两参重载方法
    public void Show1(int iParam, string sParam)
    {
        Console.WriteLine($"Show1两参数 iparam={iParam};sParam={sParam}");
    }
}
1.调用上面例子类中的 有参 或者 无参构造函数
Assembly assembly = Assembly.Load("MyReflection"); //获取当前路径下面的dl或者exe,不带后缀
Type dbHelperType = assembly.GetType("MyReflection.SqlServerHelper"); //传完整名称获类型(命名空间+类名)
//调用多个构造函数(有参,无参)
var obSqlServerHelper = Activator.CreateInstance(dbHelperType); //无参的构造函数
Activator.CreateInstance(dbHelperType, new object[] { 11 }); //int的构造函数
Activator.CreateInstance(dbHelperType, new object[] { "testbywss" }); //调用string的构造函数
Activator.CreateInstance(dbHelperType, new object[] { 123, "testbywss" }); //调用string的构造函数
2. 调用类的私有构造函数
//私有构造函数
 Type singletonType = assembly.GetType("MyReflection.Singleton"); //传入完整名称获取类型(命名空间+类名)
 var object1 = Activator.CreateInstance(singletonType, true); //设置成true能调用私有/公布的构造函数,如果不设置则只能调用公有构造函数
3.不必强制类型转换,调用 普通方法,静态方法,重载方法:

在利用了反射实例化对象之后,可以不需要强制类型转换,直接调用其方法

Type dbhelperType = assembly.GetTyp(“Ruanmou.DB.SqlServer.SqlServerHelper ”);
object obSqlServerHelper = Activator.CreateInstance(dbhelperType);

(1)普通方法

Type 类型 的对象,有一个方法 GetMethods方法,可以获取这个类型对象中所指定的方法,
如下:
MethodInfo methodInfo = dbhelperType.GetMethod(“Show”); //MethodInfo 类,用于描述方法
用获取到指定方法的 MethodInfo 对象 来调用方法
methodInfo.Invoke(obSqlServerHelper, null); //第一个参数:要调用方法的实例,普通方法必须实例化之后进行调用,上面已经用Activator.CreateInstance实例化了一个该Type的实例,这里将其传入,第二个参数:是方法需要的参数,如果没有则设置为null

(2) 静态方法调用

MethodInfo staticMethodInfo = dbHelperType.GetMethod(“Show5”); //调用单个普通的实例方法
== staticMethodInfo.Invoke(null, new object[] { “静态方法第一种调用方式” }); //第一个参数:是应用对象,如果是静态可以不用写;第二个参数:是方法需要的参数,如果没有则设置为null ==
staticMethodInfo.Invoke(obSqlServerHelper, new object[] { “静态方法第二种调用方式” });//重载方法调用

(3) 调用重载方法

重载方法
MethodInfo method2 = dbHelperType.GetMethod(“Show1”, new Type[] { }); //调用无参的函数
method2.Invoke(obSqlServerHelper, null);

MethodInfo method3 = dbHelperType.GetMethod(“Show1”, new Type[] { typeof(int) }); //int参数的方法
method3.Invoke(obSqlServerHelper, new object[] { 11 });

MethodInfo method4 = dbHelperType.GetMethod(“Show1”, new Type[] { typeof(int), typeof(string) }); //调用2个参数的方法,new Type[] { typeof(int), typeof(string) } 顺序一定要跟调用的方法的参数顺序保持一致
method4.Invoke(obSqlServerHelper, new object[] { 1111, “ddd” });

4:调用泛型
(1)首先要创建一个实体类如下:
#region 泛型类
  public class GenericClass<T, W, F>
  {
        public void Show(T t, W w, F f)
        {
            Console.WriteLine($"t.type={t.GetType().Name};}");
        }
  }

    public class GenericMethod
    {
        public void Show<T, W, X>(T t, W w, X x)
        {
            Console.WriteLine($"t.type={t.GetType().Name};");
        }
    }

    public class GenericDouble<T>
    {
        public void Show<W, X>(T t, W w, X x)
        {
            Console.WriteLine($"t.type={t.GetType().Name};");
        }
    }
    #endregion
(2)调用泛型方法如下

//创建泛型
Assembly assembly = Assembly.Load(“MyReflection”); //获取当前路径下面的dl或者exe,不带后缀
== 创建泛型类,创建泛型类的时候,除了写好类名,还要给占位符,以告诉系统这个类是一个泛型类,3个占位符,表示泛型类传入三个类型参数。==
Type genericType = assembly.GetType("MyReflection.GenericClass3"); //3是泛型类需要的参数
== 在调用实例化之前,要先指定具体的泛型的类型==
Type typeGenericNew = genericType.MakeGenericType(typeof(int), typeof(int), typeof(int)); //需要指定泛型类的类型
GenericClass<int, int, int> oGeneric = (GenericClass<int, int, int>)Activator.CreateInstance(typeGenericNew);
oGeneric.Show(1, 30, 60);

Type genericType1 = assembly.GetType(“MyReflection.GenericMethod”); //普通的类
var genericMethod = Activator.CreateInstance(genericType1) as GenericMethod;
genericMethod.Show<int, string, double>(1, “1”, 2);

5:调用私有方法
//私有方法
//调用私有方法,有参数
MethodInfo method5 = dbHelperType.GetMethod("Show5", BindingFlags.NonPublic | BindingFlags.Instance);
method5.Invoke(obSqlServerHelper, new object[] { 5.0 });

//私有方法,无参数
MethodInfo method6 = dbHelperType.GetMethod("Show6", BindingFlags.NonPublic | BindingFlags.Instance);
method6.Invoke(obSqlServerHelper, null);
6:调用普通方法的泛型方法
//类的泛型方法调用
Type genericMethodType = assembly.GetType("MyReflection.GenericMethod");
var objectGeneric = Activator.CreateInstance(genericMethodType);
MethodInfo genericMethod = genericMethodType.GetMethod("Show");
//这一步是调用泛型方法的关键,给泛型方法的参数类型指定具体类型,并告诉系统这是一个泛型方法
MethodInfo genericMethodNew = genericMethod.MakeGenericMethod(typeof(int), typeof(int));

//对泛型方法进行调用,传入的第一个参数是调用哪个实例的这个泛型方法,第二个参数是传入参数
genericMethodNew.Invoke(objectGeneric, new object[] { 1, 4 });

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值