首先反射是基于System.Reflection命名空间下,.Net框架提供的帮助类库,可以读取并使用metadata(元数据:描述对象信息的数据).

我们再来看下代码生成编译的总过程。

编译器编译(一次编译):类库生成的都是dll,控制台生成的是exe文件

dll和exe都包含两大块metadata和IL(中间语言)

dll和exe的运行环境依赖于CLR,我们安装.net frmework时会自动配置CLR和JIT(及时编译器)

JIT(二次编译(编译之后,可以在不同平台使用))会将dll和exe文件转为机器码

反射基础 

三种加载dll程序集的方法

//根据dll名称加载,不带dll后缀
Assembly assembly = Assembly.Load("Bussiness");
//完整路径加载,注意web层要引用加载的Bussiness层,如果没有依赖项,使用时会报错
Assembly assembly1 = Assembly.LoadFile(@"E:\反射\Rel\bin\Debug\netcoreapp3.1\Bussiness.dll");
//根据dll名称加载,带dll后缀
Assembly assembly2 = Assembly.Load("Bussiness.dll"); //获取该dll中的模块信息
foreach (var item in assembly.GetModules())
{
Console.WriteLine(item.FullyQualifiedName);
// => E:\反射\Rel\bin\Debug\netcoreapp3.1\Bussiness.dll
}
//获取该dll中的类型信息
foreach (var item in assembly.GetTypes())
{
Console.WriteLine(item.FullName);
// => Bussiness.Class1
// => Bussiness.Method
}

这是Bussiness层信息

根据反射创建对象

//加载程序集
Assembly assembly3 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息
Type type = assembly3.GetType("Common.StringHelper");
//创建对象
object o = Activator.CreateInstance(type);

Common层内容

当我们创建对象时,会打印 StringHelper被构造了! 因为每一个类都 自带一个构造函数,间接执行了WriteLine语句。

但是当我们调用QueryString方法时就报错了

原因是编译器不认可,编译器只把他当成是一个onject对象。

我们可以这样写

//加载程序集
Assembly assembly3 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息
Type type = assembly3.GetType("Common.StringHelper");
//创建对象
dynamic o = Activator.CreateInstance(type);
o.QueryString("今天真热");
dynamic会避开编译器的检查,相当于弱语言类型,从而达到我们的预想.
对此我们可以加以封装一下
public static StringHelper CreateHelper()
{
//加载程序集
Assembly assembly3 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息
Type type = assembly3.GetType("Common.StringHelper");
//创建对象
dynamic o = Activator.CreateInstance(type);
return o;
} //=>调用
/*
StringHelper stringHelper = Factory.CreateHelper();
await stringHelper.QueryString("开空调");
*/

反射破坏单例:单例类在内存中是唯一的,本来是不能实例化,但是可通过反射来创建对象,从而调用其私有构造函数。

public sealed class Single
{
private Single()
{
Console.WriteLine($"{this.GetType().Name}已被构造");
} private static Single single = null; public static Single CreateInstance()
{
if (single == null)
{
single = new Single();
}
return single;
}
}
//加载程序集
Assembly assembly3 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息
Type type = assembly3.GetType("Common.Single");
//创建对象
Common.Single single = (Common.Single)Activator.CreateInstance(type, true);

根据参数调用不同的构造函数

public class TestClass
{
public TestClass(string parameter)
{
Console.WriteLine($"{this.GetType().Name}已被构造");
}
public TestClass(int parameter)
{
Console.WriteLine($"{this.GetType().Name}已被构造");
}
}
//加载程序集
Assembly assembly4 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息
Type type = assembly4.GetType("Common.TestClass");
//创建对象 这里有一个参数数组,会根据参数的顺序和类型匹配对应的构造函数,如果参数是空数组或null,则构造函数不接受任何参数(无参数构造函数)
Common.TestClass single = (Common.TestClass)Activator.CreateInstance(type, );
Common.TestClass single1 = (Common.TestClass)Activator.CreateInstance(type, "");

反射操作泛型

public class GenericClass<T, R, E>
{
public void Show(T t, R r, E e)
{
Console.WriteLine($"{t.GetType().Name},{r.GetType().Name},{e.GetType().Name}");
}
}
//加载程序集
Assembly assembly4 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息 注意:`3是占位符,该泛型对象中有几个泛型参数
Type type = assembly4.GetType("Common.GenericClass`3");
//不能像这样创建对象,因为泛型对象在实例化的时候要指定参数及类型
//object o = Activator.CreateInstance(type);
//指定泛型对象的参数类型
Type type1 = type.MakeGenericType(new Type[] { typeof(decimal), typeof(Guid), typeof(Enum) });
object oGeneric = Activator.CreateInstance(type1);

调用无参方法

public class ReflectionTest
{
public void show1()
{
Console.WriteLine($"调用了{this.GetType()}中的方法show1");
}
}
//加载程序集
Assembly assembly4 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息
Type type = assembly4.GetType("Common.ReflectionTest");
//创建对象
object o = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod("show1");
//调用方法,第一个参数是实例类型,第二个是参数列表
methodInfo.Invoke(o, null);

有参方法的调用

public void show2(int i)
{
Console.WriteLine($"调用了{this.GetType()}中的方法show2");
}
//加载程序集
Assembly assembly4 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息
Type type = assembly4.GetType("Common.ReflectionTest");
//创建对象
object o = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod("show2");
//第一个参数是实例类型,第二个是参数列表
methodInfo.Invoke(o, new object[] { });

静态方法的调用

public static void show3(int i)
{
Console.WriteLine($"调用了{typeof(ReflectionTest)}中的方法show3");
}
//加载程序集
Assembly assembly4 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息
Type type = assembly4.GetType("Common.ReflectionTest");
//创建对象
object o = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod("show3");
//第一个参数是实例类型,第二个是参数列表
//因为是静态方法,所以不需要传实例对象(可传可不传),静态方法是可以通过方法名直接访问的
methodInfo.Invoke(null, new object[] { });

重载方法的调用

public static void show4()
{
Console.WriteLine($"调用了{typeof(ReflectionTest)}中的方法show4");
} public static void show4(int i)
{
Console.WriteLine($"调用了{typeof(ReflectionTest)}中的方法show4");
} public static void show4(string s)
{
Console.WriteLine($"调用了{typeof(ReflectionTest)}中的方法show4");
}
public static void show4(string s, int i)
{
Console.WriteLine($"调用了{typeof(ReflectionTest)}中的方法show4");
}
//加载程序集
Assembly assembly4 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息
Type type = assembly4.GetType("Common.ReflectionTest");
//创建对象
object o = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod("show4", new Type[] { });
//第一个参数是实例类型,第二个是参数列表
//因为是静态方法,所以不需要传实例对象(可传可不传),静态方法是可以通过方法名直接访问的
methodInfo.Invoke(null, new object[] { });
{
MethodInfo methodInfo1 = type.GetMethod("show4", new Type[] { typeof(int) });
methodInfo1.Invoke(null, new object[] { });
}
{
MethodInfo methodInfo2 = type.GetMethod("show4", new Type[] { typeof(string) });
methodInfo2.Invoke(null, new object[] { "" });
}
{
MethodInfo methodInfo3 = type.GetMethod("show4", new Type[] { typeof(string), typeof(int) });
methodInfo3.Invoke(null, new object[] { "", });
}
私有方法的调用
private void show5(string s)
{
Console.WriteLine($"调用了{typeof(ReflectionTest)}中的方法show5");
}
//加载程序集
Assembly assembly4 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息
Type type = assembly4.GetType("Common.ReflectionTest");
//创建对象
object o = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod("show5", BindingFlags.Instance | BindingFlags.NonPublic);
//第一个参数是实例类型,第二个是参数列表
methodInfo.Invoke(o, new object[] { "" });

调用泛型类中的方法

public void Show(T t, R r, E e)
{
Console.WriteLine($"{t.GetType().Name},{r.GetType().Name},{e.GetType().Name}");
}
//加载程序集
Assembly assembly4 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息 注意:`3是占位符,该泛型对象中有几个泛型参数
Type type = assembly4.GetType("Common.GenericClass`3");
//指定泛型对象的参数类型
Type type1 = type.MakeGenericType(new Type[] { typeof(double), typeof(Guid), typeof(DateTime) });
object oGeneric = Activator.CreateInstance(type1);
MethodInfo methodInfo = type1.GetMethod("Show");
methodInfo.Invoke(oGeneric, new object[] { 1.02, Guid.NewGuid(), DateTime.Now });

调用泛型类中的泛型方法

public class GenericClass<T, R, E>
{
public void Show<X>(T t, R r, E e, X x)
{
Console.WriteLine($"{t.GetType().Name},{r.GetType().Name},{e.GetType().Name},{x.GetType().Name}");
}
}
//加载程序集
Assembly assembly4 = Assembly.Load("Common");
//获取指定类型对象的(类型)信息 注意:`3是占位符,该泛型对象中有几个泛型参数
Type type = assembly4.GetType("Common.GenericClass`3");
//指定泛型对象的参数类型
Type type1 = type.MakeGenericType(new Type[] { typeof(double), typeof(Guid), typeof(DateTime) });
object oGeneric = Activator.CreateInstance(type1);
MethodInfo methodInfo = type1.GetMethod("Show");
//指定泛型方法的参数类型
MethodInfo methodInfo1 = methodInfo.MakeGenericMethod(new Type[] { typeof(string) });
methodInfo1.Invoke(oGeneric, new object[] { 1.2, Guid.NewGuid(), DateTime.Now, "" });

反射操作实体字段、属性

public class People
{
public People()
{
Console.WriteLine($"{this.GetType().FullName}构造了一次");
} public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
}
Type type = typeof(People);
object o = Activator.CreateInstance(type);
//type.GetFields()也可以,操作也是一样的
foreach (var item in type.GetProperties())
{
//Console.WriteLine(item.Name);//打印字段属性名
//Console.WriteLine(item.GetValue(o));//打印字段值
if (item.Name.Equals("id"))
item.SetValue(o, );//设置字段值
if (item.Name.Equals("name"))
item.SetValue(o, "");
Console.WriteLine($"{type.Name}.{item.Name}={item.GetValue(o)}");
}

反射映射字段,对象中字段数据转换赋值

public class People
{
public People()
{
Console.WriteLine($"{this.GetType().FullName}构造了一次");
} public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
} public class DtoPeople
{
public DtoPeople()
{
Console.WriteLine($"{this.GetType().FullName}构造了一次");
} public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
}
People people = new People();
people.id = ;
people.name = "";
people.description = ""; Type typePeople = typeof(People);
Type typeDtoPeople = typeof(DtoPeople);
//需要赋值的对象
object o = Activator.CreateInstance(typeDtoPeople);
foreach (var item in typeDtoPeople.GetFields())
{
//找出源类型字段的值 item.Name为字段属性名
object value = typePeople.GetProperty(item.Name).GetValue(people);
//赋值
item.SetValue(o, value);
}

反射的优点:动态获取对象.可扩展

反射的缺点:1.写起来复杂.2.避开编译器的检查,错误风险很大.3.性能不好

												

C# 反射详解一的更多相关文章

  1. C#反射の反射详解

    C#反射の反射详解(点击跳转)C#反射の反射接口(点击跳转)C#反射反射泛型接口(点击跳转)C#反射の一个泛型反射实现的网络请求框架(点击跳转) 一.什么是反射 反射(Reflection):这是.N ...

  2. java 反射详解

    反射的概念和原理 类字节码文件是在硬盘上存储的,是一个个的.class文件.我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个 ...

  3. Java 反射详解 转载

    java 反射 定义 功能 示例 概要: Java反射机制详解 | |目录 1反射机制是什么 2反射机制能做什么 3反射机制的相关API ·通过一个对象获得完整的包名和类名 ·实例化Class类对象 ...

  4. java反射 详解!!!!

    java反射(特别通俗易懂) 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态 ...

  5. java反射详解

    本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解. 下面开始正文. [案例1]通过一个对象 ...

  6. java反射详解(转)

    本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解. 下面开始正文. [案例1]通过一个对象 ...

  7. Java反射详解及应用示例

    反射是Java中最重要的内容之一,了解反射原理对我们学习各种框架具有很大的帮助 反射的原理: 反射应用示例: import java.lang.reflect.Constructor; import ...

  8. 【转】java反射详解

    转自:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html 本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的 ...

  9. .net反射详解(转)

    摘自:http://www.cnblogs.com/knowledgesea/archive/2013/03/02/2935920.html 概述反射 通过反射可以提供类型信息,从而使得我们开发人员在 ...

  10. 你应该知道的c# 反射详解

    C#反射 首先了解C#反射的概念,反射是一个运行库类型发现的过程.通过反射可以得到一个给定程序集所包含的所有类型的列表, 这个列表包括给定类型中定义的方法.字段.属性和事件.也可以动态的发现一组给定类 ...

随机推荐

  1. 8、HTTPS证书Actions无法导出问题

    前言 在点Actions时候出现Export Failed:The root certificate could not be located.最近有很多小伙伴在fiddler导出证书的时候,遇到无法 ...

  2. Win10系统如何分区

    前言:新买了redmibookpro 14打开此电脑后,查看到出厂时C盘分了146G其他的328G全部分到了D盘,对于平时分类比较明确的我来说这不能忍,所以开始磁盘分区. 一.右击此电脑->管理 ...

  3. 【雕爷学编程】Arduino动手做(56)---8路LED跑马灯模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  4. [Unity A*算法]A*算法的简单实现

    写在前面:之前看过一点,然后看不懂,也没用过. 最近正好重构项目看到寻路这块,想起来就去查查资料,总算稍微理解一点了,下面记录一下自己的成果(哈哈哈 :> ) 下面分享几篇我觉得挺不错的文章 A ...

  5. 全网最详细最好懂 PyTorch CNN案例分析 识别手写数字

    先来看一下这是什么任务.就是给你手写数组的图片,然后识别这是什么数字: dataset 首先先来看PyTorch的dataset类: 我已经在从零学习pytorch 第2课 Dataset类讲解了什么 ...

  6. 9.5 Go 依赖管理

    9.5 Go 依赖管理 godep是解决包依赖的管理工具,目前最主流的一种,原理是扫描记录版本控制的信息. A. 所有的第三方包都放在$GOPATH的src目录下. B. 如果不同程序依赖的版本不一样 ...

  7. Android gradle 自定义插件

    Gradle 的插件有三种打包方式: 构建脚本:插件逻辑写在 build.gradle 中,适用于逻辑简单的任务,但是该方式实现的插件在该构建脚本之外是不可见的,只能用于当前脚本. buildSrc项 ...

  8. Htop/Glances/Dstat性能测试系统监控工具领域的瑞士军刀

    原文链接:https://mp.weixin.qq.com/s/TvfzIy4uXHPOFQ1h5Q4KWg 建议点击原文链接查看 续上篇分享的[性能测试工具],今天整理了常用的系统监控工具,当然有特 ...

  9. CentOS7初始化服务器开发环境——根据个人习惯而定

    目录 修改hostname 创建个人账户和组 修改hostname 编辑主机名称,注意:执行以下指令,无需重启服务器,因为此指令实时写入linux 内核 hostnamectl --static se ...

  10. [开源] .Net orm FreeSql 1.5.0 最新版本(番号:好久不见)

    废话开头 这篇文章是我有史以来编辑最长时间的,历时 4小时!!!原本我可以利用这 4小时编写一堆胶水代码,真心希望善良的您点个赞,谢谢了!! 很久很久没有写文章了,上一次还是在元旦发布 1.0 版本的 ...