文章介绍

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

    反射:

    1. using System.Reflection;
  • 来自于System.Reflection

  • 是一个帮助类库—可以读取dll/exe中metadata和使用metadata
  • 动态的创建dll/exe —Emit技术

    传统方式

  • 定义接口

    1. public interface IDBHelper
    2. {
    3. void Query();
    4. }
  • 实现接口 ```csharp public class MySqlHelper : IDBHelper { public MySqlHelper() {

    1. Console.WriteLine($"{this.GetType().Name}被构造");

    }

  1. public void Query()
  2. {
  3. Console.WriteLine("{0}.Query", this.GetType().Name);
  4. }

}

  1. - 创建对象
  2. ```csharp
  3. IDBHelper dBHelper = new SqlServerHelper();
  4. //IDBHelper dBHelper = new MySqlHelper();
  5. //dBHelper.Query();

反射方式

  1. 动态读取Dll,三种方式

    1. Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//dll名称
    2. //Assembly assembly1 = Assembly.LoadFile(@"D:\ZXWork\Advanced15\20210706Advanced15Course02Reflection-1\Advanced.Project\MyReflecttion\bin\Debug\net5.0\Business.DB.SqlServer.dll");//dll名称
    3. //Assembly assembly2 = Assembly.Load("Business.DB.SqlServer");//dll名称
  2. 获取某一个具体的类型:参数需要是类的全名称

    1. Type type = assembly.GetType("Business.DB.SqlServer.SqlServerHelper"); //
  3. 创建对象

  • 方法一

    1. object? oInstance = Activator.CreateInstance(type);
    2. //object? oInstanc1= Activator.CreateInstance("Business.DB.SqlServer.dll", "Business.DB.SqlServer.SqlServerHelper");

    调用

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

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

  • 方法二
    如果使用dynamic 作为类型的声明,在调用的时候,没有限制;

    1. dynamic dInstance = Activator.CreateInstance(type);
    2. dInstance.Query();
    3. dInstance.Get(); //报错了--因为SqlServerHelper没有Get方法
  1. 类型转换

    1. SqlServerHelper helper = (SqlServerHelper)oInstance; //不建议这样转换--如果真实类型不一致--会报报错;
    2. IDBHelper helper = oInstance as IDBHelper;//如果类型一直,就转换,如果不一致;就返回null
  2. 调用方法

    1. helper.Query();

    初步封装

    1. public static IDBHelper CreateInstance1()
    2. {
    3. Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
    4. Type type = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");
    5. object? oInstance = Activator.CreateInstance(type);
    6. IDBHelper helper = oInstance as IDBHelper;
    7. return helper;
    8. }
  • 调用

    1. IDBHelper helper1 = SimpleFactory.CreateInstance1();
    2. helper1.Query();

    反射 SimpleFactory

  • appsetings.json

  • 始终复制appsetings.json文件

    1. "ReflictionConfig": "Business.DB.Orcale.OrcaleHelper,Business.DB.Orcale.dll",
  • 新建SimpleFactory.cs

  • 读取json字符串

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

    结果

  • 如果经理–MySql–Oracle

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

    反射破坏单例

  • 不知道有么用

    调用带参数的构造函数

    ```csharp public class ReflectionTest {

    region Identity

    1. /// <summary>
    2. /// 无参构造函数
    3. /// </summary>
    4. public ReflectionTest()

    {

    1. Console.WriteLine($"这里是{this.GetType()}无参数构造函数");

    }

    ///

    /// 带参数构造函数 /// /// public ReflectionTest(string name) {

    1. Console.WriteLine($"这里是{this.GetType()} 有参数构造函数");

    }

    public ReflectionTest(int id) {

    1. Console.WriteLine($"这里是{this.GetType()} 有参数构造函数");

    }

  1. public ReflectionTest(int id, string name)
  2. {
  3. //typeof(int);
  4. //Type //id.GetType();
  5. Console.WriteLine($"这里是{this.GetType()} 有参数构造函数");
  6. }
  7. public ReflectionTest(string name,int id )
  8. {
  9. //typeof(int);
  10. //Type //id.GetType();
  11. Console.WriteLine($"这里是{this.GetType()} 有参数构造函数");
  12. }
  13. #endregion
  14. #region Method
  15. /// <summary>
  16. /// 无参方法
  17. /// </summary>
  18. public void Show1()
  19. {
  20. Console.WriteLine($"这里是{this.GetType()}的Show1" );
  21. }
  22. /// <summary>
  23. /// 有参数方法
  24. /// </summary>
  25. /// <param name="id"></param>
  26. public void Show2(int id)
  27. {
  28. Console.WriteLine($"这里是{this.GetType()}的Show2");
  29. }
  30. /// <summary>
  31. /// 重载方法之一
  32. /// </summary>
  33. /// <param name="id"></param>
  34. /// <param name="name"></param>
  35. public void Show3(int id, string name)
  36. {
  37. Console.WriteLine($"这里是{this.GetType()}的Show3");
  38. }
  39. /// <summary>
  40. /// 重载方法之二
  41. /// </summary>
  42. /// <param name="name"></param>
  43. /// <param name="id"></param>
  44. public void Show3(string name, int id)
  45. {
  46. Console.WriteLine($"这里是{this.GetType()}的Show3_2");
  47. }
  48. /// <summary>
  49. /// 重载方法之三
  50. /// </summary>
  51. /// <param name="id"></param>
  52. public void Show3(int id)
  53. {
  54. Console.WriteLine($"这里是{this.GetType()}的Show3_3");
  55. }
  56. /// <summary>
  57. /// 重载方法之四
  58. /// </summary>
  59. /// <param name="name"></param>
  60. public void Show3(string name)
  61. {
  62. Console.WriteLine("这里是{this.GetType()}的Show3_4");
  63. }
  64. /// <summary>
  65. /// 重载方法之五
  66. /// </summary>
  67. public void Show3()
  68. {
  69. Console.WriteLine($"这里是{this.GetType()}的Show3_1");
  70. }
  71. /// <summary>
  72. /// 私有方法
  73. /// </summary>
  74. /// <param name="name"></param>
  75. private void Show4(string name) //肯定是可以的
  76. {
  77. Console.WriteLine($"这里是{this.GetType()}的Show4");
  78. }
  79. /// <summary>
  80. /// 静态方法
  81. /// </summary>
  82. /// <param name="name"></param>
  83. public static void Show5(string name)
  84. {
  85. Console.WriteLine($"这里是{typeof(ReflectionTest)}的Show5");
  86. }
  87. #endregion
  88. }
  1. - 反射调用构造函数
  2. ```csharp
  3. //Type type = null;
  4. //Activator.CreateInstance();//访问的是无参数构造函数创建对象;
  5. //如何访问带参数的构造函数呢?
  6. Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
  7. Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
  8. //a. 调用无参数构造函数的
  9. object noParaObject = Activator.CreateInstance(type);
  10. //b. 调用有参数的---需要传递一个object类型的数组作为参数,参数按照从昨往右匹配;严格匹配,按照参数的类型去执行对应的和参数类型匹配的构造函数,如果没有匹配的---报异常
  11. object paraObject = Activator.CreateInstance(type, new object[] { 123 });
  12. object paraObject1 = Activator.CreateInstance(type, new object[] { "纯洁的逗比" });
  13. object paraObject2 = Activator.CreateInstance(type, new object[] { 234, "丸印" });
  14. object paraObject3 = Activator.CreateInstance(type, new object[] { "Richard", 456 });

反射调用方法

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

    调用无参数的方法

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

    调用有参数的方法

    ```csharp 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);

  1. <a name="nnU1O"></a>
  2. #### 调用私有方法,
  3. - 在获取方法的时候,加上参数BindingFlags.NonPublic | BindingFlags.Instance
  4. ```csharp
  5. Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
  6. Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
  7. object oInstance = Activator.CreateInstance(type);
  8. MethodInfo show4 = type.GetMethod("Show4", BindingFlags.NonPublic | BindingFlags.Instance);
  9. show4.Invoke(oInstance, new object[] { "String" });

调用静态方法

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

调用泛型方法

  1. public class GenericMethod
  2. {
  3. public void Show<T, W, X>(T t, W w, X x)
  4. {
  5. Console.WriteLine($"t.type={t.GetType().Name},w.type={ w.GetType().Name},x.type={x.GetType().Name}");
  6. }
  7. }
  8. public class GenericClass<T, W, X>
  9. {
  10. public void Show(T t, W w, X x)
  11. {
  12. Console.WriteLine($"t.type={t.GetType().Name},w.type={w.GetType().Name},x.type={x.GetType().Name}");
  13. }
  14. }
  15. public class GenericDouble<T>
  16. {
  17. public void Show<W, X>(T t, W w, X x)
  18. {
  19. Console.WriteLine($"t.type={t.GetType().Name},w.type={w.GetType().Name},x.type={x.GetType().Name}");
  20. }
  21. }
  • 获取到方法后,先确定类型,严格按照参数类型传递参数就可以正常调用
  • 泛型是延迟声明,调用的时候,确定类型

    1. Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
    2. Type type = assembly.GetType("Business.DB.SqlServer.GenericMethod");
    3. object oInstance = Activator.CreateInstance(type);
    4. MethodInfo show = type.GetMethod("Show");
    5. //在执行之前选哟确定是什么类型;
    6. MethodInfo genericshow = show.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) });
    7. genericshow.Invoke(oInstance, new object[] { 123, "暖风昔人", DateTime.Now });
    8. genericshow.Invoke(oInstance, new object[] { "暖风昔人", 123, DateTime.Now });
    1. {
    2. Console.WriteLine(typeof(GenericClass<,,>));
    3. Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
    4. Type type = assembly.GetType("Business.DB.SqlServer.GenericClass`3");
    5. Type generType = type.MakeGenericType(new Type[] { typeof(int), typeof(string), typeof(DateTime) });
    6. object oInstance = Activator.CreateInstance(generType);
    7. MethodInfo show = generType.GetMethod("Show");
    8. show.Invoke(oInstance, new object[] { 123, "赤", DateTime.Now });
    9. }
    10. {
    11. Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
    12. Type type = assembly.GetType("Business.DB.SqlServer.GenericDouble`1");
    13. Type generType = type.MakeGenericType(new Type[] { typeof(int) });
    14. object oInstance = Activator.CreateInstance(generType);
    15. MethodInfo show = generType.GetMethod("Show");
    16. MethodInfo genericMethod = show.MakeGenericMethod(new Type[] { typeof(string), typeof(DateTime) });
    17. genericMethod.Invoke(oInstance, new object[] { 123, "鱼儿", DateTime.Now });
    18. }

    MVC框架

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

    反射的性能问题

  • 测试代码

  • 主要损耗性能的是加载dll 的时候会损耗性能

    1. public static void Show()
    2. {
    3. Console.WriteLine("*******************Monitor*******************");
    4. long commonTime = 0;
    5. long reflectionTime = 0;
    6. {
    7. Stopwatch watch = new Stopwatch();
    8. watch.Start();
    9. for (int i = 0; i < 1000_000; i++) //1000000000
    10. {
    11. IDBHelper iDBHelper = new SqlServerHelper();
    12. iDBHelper.Query();
    13. }
    14. watch.Stop();
    15. commonTime = watch.ElapsedMilliseconds;
    16. }
    17. {
    18. Stopwatch watch = new Stopwatch();
    19. watch.Start();
    20. Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 动态加载
    21. Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 获取类型
    22. for (int i = 0; i < 1000_000; i++)
    23. {
    24. //Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 动态加载
    25. //Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 获取类型
    26. object oDBHelper = Activator.CreateInstance(dbHelperType);//3 创建对象
    27. IDBHelper dbHelper = (IDBHelper)oDBHelper;//4 接口强制转换
    28. dbHelper.Query();//5 方法调用
    29. }
    30. watch.Stop();
    31. reflectionTime = watch.ElapsedMilliseconds;
    32. }
    33. Console.WriteLine($"commonTime={commonTime} reflectionTime={reflectionTime}");
    34. }

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

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

  • SetValue:设置值

  • GetValue:获取值
  • type.GetProperties();//属性
  • type.GetFields()//字段
  • 带有getset的叫属性, ```csharp 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”)) {
    1. prop.SetValue(pObject, 134);
    } else if (prop.Name.Equals(“Name”)) {
    1. prop.SetValue(pObject, "陈大宝");
    } else if (prop.Name.Equals(“Age”)) {
    1. prop.SetValue(pObject, 25);
    } else if (prop.Name.Equals(“Age”)) {
    1. prop.SetValue(pObject, 25);
    } }

//SetValue:设置值 //GetValue:获取值 // type.GetProperties();//属性 //type.GetFields()//字段 foreach (var prop in type.GetProperties()) { Console.WriteLine($”people.{prop.Name}={prop.GetValue(pObject)}”);

  1. if (prop.Name.Equals("Id"))
  2. {
  3. prop.GetValue(pObject);
  4. }
  5. else if (prop.Name.Equals("Name"))
  6. {
  7. prop.GetValue(pObject);
  8. }
  9. else if (prop.Name.Equals("Age"))
  10. {
  11. prop.GetValue(pObject);
  12. }

} ```

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

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

    准备条件

  • 必须有一个Id字段–继承BaseModel

  • 要求实体对象中的属性结构必须和数据完全一致

    Emit技术

    在运行时去动态的生成Dll、Exe包括dll内部的方法、属性、字段
    ————————————————
    版权声明:本文为CSDN博主「Guistar~~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/EAyayaya/article/details/124683084