6.C#知识点:反射
1.反射是什么?
反射提供描述组件,模块和类型的对象(类型为Type)。您可以使用反射来动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型,并调用其方法或访问其字段和属性。如果您在代码中使用属性,反射使您可以访问它们。有关更多信息,请参阅属性。-----来自微软官方。
微软的解释我觉得还可以。用大白话讲就是我们可以以通过反射让我们知道未知类型的信息。类似现实生活中的B超啊。医生用B超看到孕妇肚子里的内部情况,因为医生无法从内部查看。反射也是一样,对于未知类型。或者引用过来的dll。我们是不知道内部情况的。但是可以通过反射。蝙蝠的超声波也是。通过声波反射回来,得知前方是否有障碍。这就是反射的功能。如果要问反射内部是如何实现的。不好意思。目前我也不知道。哈哈哈哈。
简单的来说,我们的程序是由dll的组成的,dll里面有许许多多的类组成。类里面又有字段,属性和方法。反射的作用就是给个dll就能知道有哪些类,通过类又能知道有哪些成员。那么.net里面的反射是怎么做到呢?那下面就要介绍几个种类的反射类了。
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。这段话是从大牛的博客拷贝------->传送门
下面我依次重点的介绍几个详细的类。
首先是Assembly。这个存在于System.Reflection命名空间下面。我主要讲它的3个加载程序集的的方法和区别。Load,LoadForm,LoadFile。
讲了这么多文字,先从代码看看语法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; namespace 反射Demo
{
class Program
{
static void Main(string[] args)
{
//加载程序集
Assembly assembly = Assembly.Load("TestDLL"); //输出程序集的强名称
Console.WriteLine(assembly.FullName);
Console.ReadKey();
}
}
}

Load方法就是通过程序集的的名称加载程序,但是需要要加载的程序集在当前程序集的bin目录下才能找得到。
LoadForm
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; namespace 反射Demo
{
class Program
{
static void Main(string[] args)
{
#region Load方法
//加载程序集
// Assembly assembly = Assembly.Load("TestDLL"); //输出程序集的强名称
//Console.WriteLine(assembly.FullName);
//Console.ReadKey();
#endregion Assembly assmbly1 = Assembly.LoadFrom(@"C:\Users\DH\Documents\visual studio 2017\Projects\反射Demo\TestDLL\bin\Debug\TestDLL.dll");
Console.WriteLine(assmbly1.FullName);
Console.ReadKey();
}
}
}
LoadForm是通过路径进行创建。返回加载的程序集。
来看最后一个loadFile
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; namespace 反射Demo
{
class Program
{
static void Main(string[] args)
{
#region Load方法
//加载程序集
// Assembly assembly = Assembly.Load("TestDLL"); //输出程序集的强名称
//Console.WriteLine(assembly.FullName);
//Console.ReadKey();
#endregion #region LoadFrom方法
//Assembly assmbly1 = Assembly.LoadFrom(@"C:\Users\DH\Documents\visual studio 2017\Projects\反射Demo\TestDLL\bin\Debug\TestDLL.dll");
//Console.WriteLine(assmbly1.FullName);
///Console.ReadKey();
#endregion #region LoadFile方法
Assembly assmbly2 = Assembly.LoadFile(@"C:\Users\DH\Documents\visual studio 2017\Projects\反射Demo\TestDLL\bin\Debug\TestDLL.dll");
Console.WriteLine(assmbly2.FullName);
Console.ReadKey();
#endregion
}
}
}
这个三个方法语法都很简单。现在来说说这个三个的区别,和优缺点。
LoadFrom和Load:LoadForm同一个程序集只加载一次,就算加载了不通的路径相同的程序集,他也只能给你返回之前的程序集,LoadFrom只能用于加载不同标识的程序集, 也就是唯一的程序集, 不能用于加载标识相同但路径不同的程序集。
LoadFile和LoadForm:loadFile只会加载本身程序集,不会加在其引用的程序集,LoadForm和Load是会加载的其引用程序集。而且LoadFile同一个程序集只能加载一次。这个和LoadForm是一样。
从性能上看 LoadForm没有Load好,功能上也是load强一点。应用的时候如果loadFom和load都满足需求,建议用load。
这几个方法还几个重载版本。由于本片只是基础篇。篇幅不宜过多。想深入了解的小伙伴可以查询MSN看看文档。最详细的说明就是文档。但是文档说的比较官方。结合大牛们写的博客。更容易懂一点。
好了我们开始下一个阶段了。程序集现在我们得了。我开始看看程序集里面有些啥?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; namespace 反射Demo
{
class Program
{
static void Main(string[] args)
{ #region LoadFrom方法
Assembly assmbly = Assembly.LoadFrom(@"C:\Users\DH\Documents\visual studio 2017\Projects\反射Demo\TestDLL\bin\Debug\TestDLL.dll");
Type[] types = assmbly.GetTypes();
foreach (var item in types)
{
Console.WriteLine("类:"+item.Name); }
Console.ReadKey();
#endregion }
}
}

assmbly.GetTypes()这个方法或获取了所有类。
下面我我展示下获取字段和方法的字段
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; namespace 反射Demo
{
class Program
{
static void Main(string[] args)
{ #region LoadFrom方法
Assembly assmbly = Assembly.LoadFrom(@"C:\Users\DH\Documents\visual studio 2017\Projects\反射Demo\TestDLL\bin\Debug\TestDLL.dll");
Type[] types = assmbly.GetTypes();
foreach (var classitem in types)
{
Console.WriteLine("类:"+ classitem.Name);
foreach (var fileditem in classitem.GetFields())
{
Console.WriteLine("字段名:"+ fileditem.Name);
}
foreach (var methodItem in classitem.GetMethods())
{
Console.WriteLine("方法名:"+methodItem.Name);
} }
Console.ReadKey();
#endregion }
}
}
可以看的出来我们将字段和方法名都给反射出来了,但是有个问题就是我们父类的方法也给弄出来了。我们可以修改下。这个地方有个重载版本。GetMethods有个重载方法可以通过BindingFlags枚举参数进行筛选父类的方法,或者其他的。 BindingFlags这个枚举类型。这里就不多讲。未来我会慢慢补全。
简单的就是这么多了。反射能做好多事情,非常灵活。我们抽象工厂里面就会用到反射。我们的工厂。就是通过反射创建出来。下面我写个demo演示下其作用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TestDLL; namespace 反射Demo
{
class Program
{
static void Main(string[] args)
{
Assembly assmbly = Assembly.Load("TestDLL");
SqlServerHelper helper =(SqlServerHelper)assmbly.CreateInstance("TestDLL.SqlServerHelper");
helper.Query();
Console.ReadKey();
}
}
}
小伙伴们可以发现。我们实例化了一个SqlServerHelper对象,但是我们没有用正常的new方法,而是用了反射。这个时候有的小伙伴可能就会说这是脱裤子放屁,直接new多简单。在这里是没错,但是放在真正的项目里直接new是当时爽,需求变动就等着哭吧,比如说以后领导对你说,公司的数据库不用SqlServer了,换成Oracle了。这是时候如果你是new的话还要改这里的代码,实际情况可能更复杂。但是用了我们的反射,这种烦恼就不会存在了。
CreateInstance("TestDLL.SqlServerHelper") 这个方法参数我们完全可以通过配置文件修改。这个类就不需要变了。我来演示下代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace TestDLL
{
public interface IDBHelper
{
void Query();
}
}
先创建一个约定数据操作的接口 IDBHlper类。规定有一个Query方法,然后让SqlServerHelper继承这个接口,并且实现这个方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace TestDLL
{
public class SqlServerHelper: IDBHelper
{
public void Query()
{
Console.WriteLine("这是测试");
}
}
}
然后修改mian函数的方法
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="Helper" value="TestDLL.SqlServerHelper"/>
</appSettings>
</configuration>
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TestDLL; namespace 反射Demo
{
class Program
{
static void Main(string[] args)
{
Assembly assmbly = Assembly.Load("TestDLL");
string helperkey = ConfigurationManager.AppSettings["Helper"];
IDBHelper helper =(IDBHelper)assmbly.CreateInstance(helperkey);
helper.Query();
Console.ReadKey();
}
}
}
这时候如果要将mian函数里面helper切换成Oracle的只要添加一个继承于IDBheper接口的类,然后实现方法,在修改配置文件指向这个类,然后就可以了。对于main函数我们是一点不需要动的,这是就是我们所有的高内聚低耦合。完成解耦。易于修改。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace TestDLL
{
public class OracleHelper : IDBHelper
{
public void Query()
{
Console.WriteLine("我是Orcle数据库");
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="Helper" value="TestDLL.OracleHelper"/>
</appSettings>
</configuration>
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TestDLL; namespace 反射Demo
{
class Program
{
static void Main(string[] args)
{
Assembly assmbly = Assembly.Load("TestDLL");
string helperkey = ConfigurationManager.AppSettings["Helper"];
IDBHelper helper =(IDBHelper)assmbly.CreateInstance(helperkey);
helper.Query();
Console.ReadKey();
}
}
}
mian函数一点都没有变化。运行查看结果

到了这个里,我已经演示了一个反射应用场景了。其实VS本身就很多地方用了反射。比如。创建对象调用方法时候
VS直接只能帮我们列出这个对象下的成员。这个就是通过反射。其实还有很多。等待大家去发现。反射应该属于C#里面的高级知识点了。目前所说的只是冰山一角。
Ok。讲到这里就结束了哈。
如果刚开始学习的小伙伴还有疑问的话,可以评论咱们一起学习。
如果哪位大牛随便瞄到个错误,也请告之我,让我能够进步。
6.C#知识点:反射的更多相关文章
- 跟着刚哥梳理java知识点——反射和代理(十七)
反射机制是什么?反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有的属性和方法:对于任意一个对象,都能够调用他的一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语 ...
- Java基础重要知识点-反射
反射,如何把.java文件转化为.class文件 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信 ...
- C#知识点-反射
一.开发环境 操作系统:Win7 编译器:VS2010 .net版本:.net4.0 二.项目结构 三.开发流程 0.编写实体类 namespace ReflectDemo { public clas ...
- 小白也能看懂的插件化DroidPlugin原理(二)-- 反射机制和Hook入门
前言:在上一篇博文<小白也能看懂的插件化DroidPlugin原理(一)-- 动态代理>中详细介绍了 DroidPlugin 原理中涉及到的动态代理模式,看完上篇博文后你就会发现原来动态代 ...
- 反射的妙用:C#通过反射动态生成类型继承接口并实现
起因 最近想自己鼓捣个RPC,想着简化RPC调用方式,直接申明接口,然后根据接口的属性去配置RPC调用的相关信息.有一种说法叫申明式调用. 简单来说就是,申明一个interface,动态继承并实例化, ...
- Java程序员都要懂得知识点:反射
摘要:Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语 ...
- Java基础--反射机制的知识点梳理
什么是反射? 正常编译执行java文件时,会生成一个.class文件,反射就是一个反编译的过程,它可以通过.class文件得到一个java对象.一个类会有很多组成部分,比如成员变量,成员方法,构造方法 ...
- java 反射,注解,泛型,内省(高级知识点)
Java反射 1.Java反射是Java被视为动态(或准动态)语言的一个关键性质.这个机制允许程序在运行时透过Reflection APIs 取得任何一个已知名称的class的内部信息, 包括 ...
- JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]
类的继承 Java只支持单继承,不允许多重继承- 一个子类只能有一个父类- 一个父类可以派生出多个子类这里写图片描述子类继承了父类,就继承了父类的方法和属性.在子类中,可以使用父类中定义的方法和属性, ...
随机推荐
- Python 数据结构与算法—— 快排
1. 先从待排序的数组中找出一个数作为基准数(取第一个数即可),然后将原来的数组划分成两部分:小于基准数的左子数组和大于等于基准数的右子数组.然后对这两个子数组再递归重复上述过程,直到两个子数组的所有 ...
- JS学习笔记2_面向对象
1.对象的定义 ECMAScript中,对象是一个无序属性集,这里的“属性”可以是基本值.对象或者函数 2.数据属性与访问器属性 数据属性即有值的属性,可以设置属性只读.不可删除.不可枚举等等 访问器 ...
- System.Data.SQLite安装的相关问题
在使用System.Data.SQLite的过程中,遇到各种问题,特此记录下.(都被搞的折寿了,不仔细看文档的下场!) 1.选对.net Framework的版本. 2.X64和X86的问题,如果项目 ...
- ViewPager无限滑动
2016-6-19 前言 View轮播效果在app中很常见,一想到左右滑动的效果就很容易想到使用ViewPager来实现.对于像我们常说的banner这样的效果,具备无限滑动的功能是可以用ViewPa ...
- 《UNIX环境网络编程》第十四章第14.9小结(bug)
1.源代码中的<sys/devpoll.h>头文件在我的CentOS7系统下的urs/include/sys/目录下没有找到. 而且我的CentOS7也不存在这个/dev/poll文件. ...
- MyEclipse 编写 JSP 代码时很卡的解决办法
在网上看到很多方法,都是尝试过,个人感觉都没有说到重点,所以收效甚微. 后来自己总结了一下: 我们都是习惯在MyEclipse 工具,双击jsp 文件打开进行编辑.这时,工具会打开窗口的 Previe ...
- Oracle 查看当前数据库版本的方法
常用的有三种方法: 方法一:v$version SQL> select * from v$version; BANNER ---------------------------------- ...
- Android的Fragment的第一种声明方式
Android的Frangment的第一种声明方式 实际效果图如下: 项目结构图如下: fragment1: package com.demo.fragementfirst; import andro ...
- Spring Cloud Eureka 实现服务注册与发现
微服务 是一种架构模式,跟具体的语言实现无关,微服务架构将业务逻辑分散到了各个服务当中,服务间通过网络层进行通信共同协作:这样一个应用就可以划分为多个服务单独来维护发布.构建一个可靠微服务系统是需要具 ...
- CentOS 7 安装配置 Gitlab
centos:http://www.centos.org/download/ download:https://about.gitlab.com/downloads/ update:https://g ...
