您的位置:首页 > 其它

.NET 反射原理及其运用

2019-03-23 13:00 381 查看

一.何谓反射

反射:是.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(obSqlServer 4000 Helper, 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.GenericClass

3"); //
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 });

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: