C# 反射

  • 文章介绍
  • 开源资源连接
  • 反射:
    • 传统方式
    • 反射方式
      • 初步封装
    • 反射 SimpleFactory
    • 反射破坏单例
    • 调用带参数的构造函数
    • 反射调用方法
      • 调用无参数的方法
      • 调用有参数的方法
      • 调用私有方法,
      • 调用静态方法,
      • 调用泛型方法
  • MVC框架
  • 反射的性能问题
  • 反射如何给属性字段设置值和取值?
  • 反射+ADO.NET时间数据库访问层---手写ORM框架
    • 准备条件
  • Emit技术

文章介绍

  • 学习笔记,基于朝夕教育VIP班课程
  • 文章写的不好,自己看

开源资源连接

源码地址,推荐直接看源码

反射:

using System.Reflection;
  • 来自于System.Reflection
  • 是一个帮助类库—可以读取dll/exe中metadata和使用metadata
  • 动态的创建dll/exe —Emit技术

传统方式

  • 定义接口
public interface IDBHelper
{void Query();
}
  • 实现接口
public class MySqlHelper : IDBHelper
{public MySqlHelper(){Console.WriteLine($"{this.GetType().Name}被构造");}public void Query(){Console.WriteLine("{0}.Query", this.GetType().Name);}
}
  • 创建对象
IDBHelper dBHelper = new SqlServerHelper();
//IDBHelper dBHelper = new MySqlHelper();
//dBHelper.Query();

反射方式

  1. 动态读取Dll,三种方式
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//dll名称
//Assembly assembly1 = Assembly.LoadFile(@"D:\ZXWork\Advanced15\20210706Advanced15Course02Reflection-1\Advanced.Project\MyReflecttion\bin\Debug\net5.0\Business.DB.SqlServer.dll");//dll名称
//Assembly assembly2 = Assembly.Load("Business.DB.SqlServer");//dll名称
  1. 获取某一个具体的类型:参数需要是类的全名称
Type type = assembly.GetType("Business.DB.SqlServer.SqlServerHelper"); //
  1. 创建对象
  • 方法一
object? oInstance = Activator.CreateInstance(type);
//object? oInstanc1= Activator.CreateInstance("Business.DB.SqlServer.dll", "Business.DB.SqlServer.SqlServerHelper");

调用

a.oInstance.Query();//报错了:

因为: oInstance当做是一个object类型,object类型是没有Query方法;C#语言是一种强类型语言;编译时决定你是什么类型,以左边为准;不能调用是因为编译器不允许;实际类型一定是SqlServerHelper;

  • 方法二
    如果使用dynamic 作为类型的声明,在调用的时候,没有限制;
dynamic dInstance = Activator.CreateInstance(type);
dInstance.Query();
dInstance.Get(); //报错了--因为SqlServerHelper没有Get方法
  1. 类型转换
 SqlServerHelper helper = (SqlServerHelper)oInstance; //不建议这样转换--如果真实类型不一致--会报报错;
IDBHelper helper = oInstance as IDBHelper;//如果类型一直,就转换,如果不一致;就返回null
  1. 调用方法
helper.Query();

初步封装

public static IDBHelper CreateInstance1()
{Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); Type type = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");object? oInstance = Activator.CreateInstance(type);IDBHelper helper = oInstance as IDBHelper;return helper;
}
  • 调用
IDBHelper helper1 = SimpleFactory.CreateInstance1();
helper1.Query();

反射 SimpleFactory

  • appsetings.json
  • 始终复制appsetings.json文件
"ReflictionConfig": "Business.DB.Orcale.OrcaleHelper,Business.DB.Orcale.dll",
  • 新建SimpleFactory.cs
  • 读取json字符串
public static class CustomConfigManager
{//Core 读取配置文件:appsettings//1.Microsoft.Extensions.Configuration;//2.Microsoft.Extensions.Configuration.Json public static string GetConfig(string key){var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");  //默认读取  当前运行目录IConfigurationRoot configuration = builder.Build();string configValue = configuration.GetSection(key).Value;return configValue;}
}
public class SimpleFactory
{//创建SqlServerHelper的时候,没有出现SqlserverHelper;没有依赖SqlServerHelper//依赖的是两个字符串Business.DB.SqlServer.dll + Business.DB.SqlServer.SqlServerHelper//去掉个对细节的依赖的;依赖于抽象--不再依赖于细节;----依赖倒置原则; 增强代码的稳定性;public static IDBHelper CreateInstance(){  string ReflictionConfig = CustomConfigManager.GetConfig("ReflictionConfig"); //Business.DB.SqlServer.SqlServerHelper,Business.DB.SqlServer.dll string typeName = ReflictionConfig.Split(',')[0];string dllName = ReflictionConfig.Split(',')[1];//Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll"); //Type type = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");Assembly assembly = Assembly.LoadFrom(dllName); Type type = assembly.GetType(typeName);object? oInstance = Activator.CreateInstance(type);IDBHelper helper = oInstance as IDBHelper; return helper; }
}

结果

  • 如果经理–MySql–Oracle
  • 如果一个新的功能还不存在,只需要把功能实现、dll Copy到执行目录下,修改配置文件-- - 不需要停止程序的运行;
  • 扩展一个新的功能进来;

反射破坏单例

  • 不知道有么用

调用带参数的构造函数

 public class ReflectionTest{#region Identity/// <summary>/// 无参构造函数/// </summary>public ReflectionTest(){Console.WriteLine($"这里是{this.GetType()}无参数构造函数");}/// <summary>/// 带参数构造函数/// </summary>/// <param name="name"></param>public ReflectionTest(string name){Console.WriteLine($"这里是{this.GetType()} 有参数构造函数");}public ReflectionTest(int id){Console.WriteLine($"这里是{this.GetType()} 有参数构造函数");}public ReflectionTest(int id, string name){//typeof(int);//Type //id.GetType();Console.WriteLine($"这里是{this.GetType()} 有参数构造函数");}public ReflectionTest(string name,int id ){//typeof(int);//Type //id.GetType();Console.WriteLine($"这里是{this.GetType()} 有参数构造函数");}#endregion#region Method/// <summary>/// 无参方法/// </summary>public void Show1(){Console.WriteLine($"这里是{this.GetType()}的Show1" );}/// <summary>/// 有参数方法/// </summary>/// <param name="id"></param>public void Show2(int id){Console.WriteLine($"这里是{this.GetType()}的Show2");}/// <summary>/// 重载方法之一/// </summary>/// <param name="id"></param>/// <param name="name"></param>public void Show3(int id, string name){Console.WriteLine($"这里是{this.GetType()}的Show3");}/// <summary>/// 重载方法之二/// </summary>/// <param name="name"></param>/// <param name="id"></param>public void Show3(string name, int id){Console.WriteLine($"这里是{this.GetType()}的Show3_2");}/// <summary>/// 重载方法之三/// </summary>/// <param name="id"></param>public void Show3(int id){Console.WriteLine($"这里是{this.GetType()}的Show3_3");}/// <summary>/// 重载方法之四/// </summary>/// <param name="name"></param>public void Show3(string name){Console.WriteLine("这里是{this.GetType()}的Show3_4");}/// <summary>/// 重载方法之五/// </summary>public void Show3(){Console.WriteLine($"这里是{this.GetType()}的Show3_1");}/// <summary>/// 私有方法/// </summary>/// <param name="name"></param>private void Show4(string name)  //肯定是可以的{Console.WriteLine($"这里是{this.GetType()}的Show4");}/// <summary>/// 静态方法/// </summary>/// <param name="name"></param>public static void Show5(string name){Console.WriteLine($"这里是{typeof(ReflectionTest)}的Show5");}#endregion}
  • 反射调用构造函数
//Type type = null;
//Activator.CreateInstance();//访问的是无参数构造函数创建对象;
//如何访问带参数的构造函数呢?
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
//a. 调用无参数构造函数的
object noParaObject = Activator.CreateInstance(type);
//b. 调用有参数的---需要传递一个object类型的数组作为参数,参数按照从昨往右匹配;严格匹配,按照参数的类型去执行对应的和参数类型匹配的构造函数,如果没有匹配的---报异常
object paraObject = Activator.CreateInstance(type, new object[] { 123 });
object paraObject1 = Activator.CreateInstance(type, new object[] { "纯洁的逗比" });
object paraObject2 = Activator.CreateInstance(type, new object[] { 234, "丸印" });
object paraObject3 = Activator.CreateInstance(type, new object[] { "Richard", 456 });

反射调用方法

  • 反射调用构造函数
  • 执行MethodInfo 的Invoke方法,传递方法所在的类的实例对象+参数

调用无参数的方法

Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
object oInstance = Activator.CreateInstance(type);
MethodInfo show1 = type.GetMethod("Show1");
show1.Invoke(oInstance, new object[] { });
show1.Invoke(oInstance, new object[0]);
show1.Invoke(oInstance, null);

调用有参数的方法

Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");//一个int
object oInstance = Activator.CreateInstance(type);
MethodInfo show2 = type.GetMethod("Show2");
show2.Invoke(oInstance, new object[] { 123 });//STRING INT
MethodInfo show31 = type.GetMethod("Show3", new Type[] { typeof(string), typeof(int) });
show31.Invoke(oInstance, new object[] { "细雨浮萍", 234 });MethodInfo show32 = type.GetMethod("Show3", new Type[] { typeof(int) });
show32.Invoke(oInstance, new object[] { 345 });MethodInfo show33 = type.GetMethod("Show3", new Type[] { typeof(string) });
show33.Invoke(oInstance, new object[] { "幸福靓装" });MethodInfo show34 = type.GetMethod("Show3", new Type[0]);
show34.Invoke(oInstance, null);

调用私有方法,

  • 在获取方法的时候,加上参数BindingFlags.NonPublic | BindingFlags.Instance
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
object oInstance = Activator.CreateInstance(type);
MethodInfo show4 = type.GetMethod("Show4", BindingFlags.NonPublic | BindingFlags.Instance);
show4.Invoke(oInstance, new object[] { "String" });

调用静态方法,

//ReflectionTest.Show5();
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
object oInstance = Activator.CreateInstance(type);
MethodInfo show5 = type.GetMethod("Show5");
show5.Invoke(null, new object[] { "String" });
show5.Invoke(oInstance, new object[] { "String" });

调用泛型方法

public class GenericMethod
{public void Show<T, W, X>(T t, W w, X x){Console.WriteLine($"t.type={t.GetType().Name},w.type={ w.GetType().Name},x.type={x.GetType().Name}");}
}public class GenericClass<T, W, X>
{public void Show(T t, W w, X x){Console.WriteLine($"t.type={t.GetType().Name},w.type={w.GetType().Name},x.type={x.GetType().Name}");}
}public class GenericDouble<T>
{public void Show<W, X>(T t, W w, X x){Console.WriteLine($"t.type={t.GetType().Name},w.type={w.GetType().Name},x.type={x.GetType().Name}");}
}
  • 获取到方法后,先确定类型,严格按照参数类型传递参数就可以正常调用
  • 泛型是延迟声明,调用的时候,确定类型
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.GenericMethod");
object oInstance = Activator.CreateInstance(type);
MethodInfo show = type.GetMethod("Show");
//在执行之前选哟确定是什么类型;
MethodInfo genericshow = show.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) });
genericshow.Invoke(oInstance, new object[] { 123, "暖风昔人", DateTime.Now });
genericshow.Invoke(oInstance, new object[] { "暖风昔人", 123, DateTime.Now });
{Console.WriteLine(typeof(GenericClass<,,>));Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");Type type = assembly.GetType("Business.DB.SqlServer.GenericClass`3");Type generType = type.MakeGenericType(new Type[] { typeof(int), typeof(string), typeof(DateTime) });object oInstance = Activator.CreateInstance(generType);MethodInfo show = generType.GetMethod("Show");show.Invoke(oInstance, new object[] { 123, "赤", DateTime.Now });
}
{Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");Type type = assembly.GetType("Business.DB.SqlServer.GenericDouble`1");Type generType = type.MakeGenericType(new Type[] { typeof(int) });object oInstance = Activator.CreateInstance(generType);MethodInfo show = generType.GetMethod("Show");MethodInfo genericMethod = show.MakeGenericMethod(new Type[] { typeof(string), typeof(DateTime) });genericMethod.Invoke(oInstance, new object[] { 123, "鱼儿", DateTime.Now });
}

MVC框架

http://localhost:64527/Home/Index 就可以调用到Index方法

反射的性能问题

  • 测试代码
  • 主要损耗性能的是加载dll 的时候会损耗性能
 public static void Show(){Console.WriteLine("*******************Monitor*******************");long commonTime = 0;long reflectionTime = 0;{Stopwatch watch = new Stopwatch();watch.Start();for (int i = 0; i < 1000_000; i++) //1000000000{IDBHelper iDBHelper = new SqlServerHelper();iDBHelper.Query();}watch.Stop();commonTime = watch.ElapsedMilliseconds;}{Stopwatch watch = new Stopwatch();watch.Start();Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 动态加载Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 获取类型  for (int i = 0; i < 1000_000; i++){//Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 动态加载//Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 获取类型  object oDBHelper = Activator.CreateInstance(dbHelperType);//3 创建对象IDBHelper dbHelper = (IDBHelper)oDBHelper;//4 接口强制转换dbHelper.Query();//5 方法调用}watch.Stop();reflectionTime = watch.ElapsedMilliseconds;}Console.WriteLine($"commonTime={commonTime} reflectionTime={reflectionTime}");}

反射如何给属性字段设置值和取值?

如果说People增加一个字段呢?增加一个属性呢?
!
普通方法就必须要修改代码—重新编译发布----不稳定

  • SetValue:设置值
  • GetValue:获取值
  • type.GetProperties();//属性
  • type.GetFields()//字段
  • 带有getset的叫属性,
    Type type = typeof(People);object pObject = Activator.CreateInstance(type);//pObject.Id=234; foreach (var prop in type.GetProperties()){//Console.WriteLine(prop.Name);//逐个属性赋值if (prop.Name.Equals("Id")){prop.SetValue(pObject, 134);}else if (prop.Name.Equals("Name")){prop.SetValue(pObject, "陈大宝");}else if (prop.Name.Equals("Age")){prop.SetValue(pObject, 25);}else if (prop.Name.Equals("Age")){prop.SetValue(pObject, 25);}}//SetValue:设置值//GetValue:获取值// type.GetProperties();//属性//type.GetFields()//字段foreach (var prop in type.GetProperties()){Console.WriteLine($"people.{prop.Name}={prop.GetValue(pObject)}");if (prop.Name.Equals("Id")){prop.GetValue(pObject);}else if (prop.Name.Equals("Name")){prop.GetValue(pObject);}else if (prop.Name.Equals("Age")){prop.GetValue(pObject);}}
}

反射+ADO.NET时间数据库访问层—手写ORM框架

  • ORM–对象关系映射
  • 可以通过依赖于某个实体对象–做到对数据库中数据的操作

准备条件

  • 必须有一个Id字段–继承BaseModel
  • 要求实体对象中的属性结构必须和数据完全一致

Emit技术

在运行时去动态的生成Dll、Exe包括dll内部的方法、属性、字段

【C# 】反射,调用.dll文件里面的方法相关推荐

  1. java中调用dll文件的两种方法

    https://www.cnblogs.com/huozhong/p/5830485.html JNA地址:http://blog.csdn.net/shendl/article/details/35 ...

  2. java如何利用JNative调用dll文件

    下文参考自:http://blog.163.com/wex660@126/blog/static/2415306520103142363964/ 因为项目需要,用到了java调用dll文件中的方法.写 ...

  3. vs 2017 制作Dll文件的两种方法,以及调用Dll文件的两种方法。

    近来学习制作Dll文件,看了几个视频教程,看了网上的例子,看了msdn上的例子.现在做个总结,以便来日回顾,同时也希望以大家相互交流学习. 注意1:用 method 1 named "Usi ...

  4. 转【C#调用DLL的几种方法,包括C#调用C\C++\C#DLL】

    C#中dll调用方法 一.      DLL与应用程序 动态链接库(也称为DLL,即为"Dynamic Link Library"的缩写)是Microsoft Windows最重要 ...

  5. C#调用DLL的几种方法

    c#中dll调用方法 一. DLL与应用程序 动态链接库(也称为DLL,即为"Dynamic Link Library"的缩写)是Microsoft Windows最重要的组成要素 ...

  6. C++调用dll文件步骤

    一.基本知识 1.DLL是一个包含可由多个程序同时使用的代码和数据的库.使用dll可以提高代码的复用率,简化部署与安装. 二.使用方法 使用封装好的dll文件有两种方式,一种需要lib库:另一种不需要 ...

  7. labview如何加载库_LabVIEW如何方便地调用DLL文件

    转自:http://bbs.elecfans.com/jishu_469502_1_1.html LabVIEW调用DLL文件 LabVIEW支持通过调用DLL文件的方式与其它编程语言混合使用.比如, ...

  8. java jni dll路径_Java中Jni调用DLL文件试验

    Java中Jni调用DLL文件试验 下面是小编整理的Java中Jni调用DLL文件试验内容,希望可以为您带来帮助!更多内容请关注应届毕业生考试网! 所有文件均在E:\路径下. 安装jdk1.6.0_0 ...

  9. jar调用dll文件提示找不到指定的模块Unable to load library

    目录 问题描述 解决方案一 解决方案二 效果 补充说明 参考链接 问题描述 在Windows系统上,自己开发的需要使用JNA调用动态链接库dll文件的Swing项目(Java简易系统监视器system ...

最新文章

  1. 华为某研究生程序员哀叹:年薪五十多万,存款一百万,却不知道未来怎么走!...
  2. SpringBoot 拦截器和过滤器
  3. 自拟计算机作文100字,我的电脑作文100字五篇
  4. JavaScript 秘密花园[转]
  5. 选数(洛谷-P1036)
  6. redis集群实现(六) 容灾与宕机恢复
  7. Codeforces Round #465 (Div. 2) F. Fafa and Array
  8. python 2 版本中的input() 和 raw_input() 函数的比较
  9. TClientDataSet[2]: Data、XMLData
  10. Java并发编程之安全发布对象的四种方法
  11. android offtime编程,OFFTIME - 做功课就憋玩手机了! - Android 应用 - 【最美应用】
  12. axure元件制作-常用开关
  13. 学生没有教育邮箱如何享受Jetbrains全家桶优惠(白嫖)
  14. 解决vue项目重复点击跳转路由报错以及路由重定向的问题
  15. Spring SpringMVC SpringBoot SpringCloud概念及关系
  16. Charles常用抓包用具安装及使用
  17. Google CSE帮你多站点同时站内搜索
  18. 10.Vue.js前端框架:过渡
  19. STM32与GSM800A调试记录
  20. 【陨石坠落的速度是每秒10千米】

热门文章

  1. 公司无线局域网安全解决方案
  2. CentOS下安装微软雅黑字体
  3. 好书赠送丨海伦·尼森鲍姆著:《场景中的隐私——技术、政治和社会生活中的和谐》,王苑等译
  4. 正态分布在项目工期预期概率中的考点及其它领域的应用
  5. macOS 必备软件之系统监控工具「iStat Menus」
  6. 2022年全球慢性病护理管理软件行业分析报告
  7. 三、Zstack云平台快速安装与初始化(ZCCT云计算认证)
  8. 架构系列之标准Web系统的架构分层
  9. 机房收费管理程序c语言,C语言机房收费管理系统
  10. PS调出米黄色复古柔和外景人物照