文章介绍
- 学习笔记,基于朝夕教育VIP班课程
-
反射:
using System.Reflection;
来自于System.Reflection
- 是一个帮助类库—可以读取dll/exe中metadata和使用metadata
-
传统方式
定义接口
public interface IDBHelper
{
void Query();
}
实现接口 ```csharp public class MySqlHelper : IDBHelper { public MySqlHelper() {
Console.WriteLine($"{this.GetType().Name}被构造");
}
public void Query()
{
Console.WriteLine("{0}.Query", this.GetType().Name);
}
}
- 创建对象
```csharp
IDBHelper dBHelper = new SqlServerHelper();
//IDBHelper dBHelper = new MySqlHelper();
//dBHelper.Query();
反射方式
动态读取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名称
获取某一个具体的类型:参数需要是类的全名称
Type type = assembly.GetType("Business.DB.SqlServer.SqlServerHelper"); //
创建对象
方法一
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方法
类型转换
SqlServerHelper helper = (SqlServerHelper)oInstance; //不建议这样转换--如果真实类型不一致--会报报错;
IDBHelper helper = oInstance as IDBHelper;//如果类型一直,就转换,如果不一致;就返回null
调用方法
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到执行目录下,修改配置文件— - 不需要停止程序的运行;
-
反射破坏单例
-
调用带参数的构造函数
```csharp public class ReflectionTest {
region Identity
/// <summary>
/// 无参构造函数
/// </summary>
public ReflectionTest()
{
Console.WriteLine($"这里是{this.GetType()}无参数构造函数");
}
///
/// 带参数构造函数 /// /// 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
}
- 反射调用构造函数
```csharp
//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);
调用有参数的方法
```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);
<a name="nnU1O"></a>
#### 调用私有方法,
- 在获取方法的时候,加上参数BindingFlags.NonPublic | BindingFlags.Instance
```csharp
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的叫属性,
```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”))
{
} else if (prop.Name.Equals(“Name”)) {prop.SetValue(pObject, 134);
} else if (prop.Name.Equals(“Age”)) {prop.SetValue(pObject, "陈大宝");
} else if (prop.Name.Equals(“Age”)) {prop.SetValue(pObject, 25);
} }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内部的方法、属性、字段
————————————————
版权声明:本文为CSDN博主「Guistar~~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/EAyayaya/article/details/124683084