[.net 面向对象程序设计进阶] (20) 反射(Reflection)(上)利用反射技术实现动态编程
[.net 面向对象程序设计进阶] (20) 反射(Reflection)(上)利用反射技术实现动态编程
本节导读:本节主要介绍什么是.NET反射特性,.NET反射能为我们做些什么,最后介绍几种常用的反射的实现方法,通过对反射性特的了解,可以设计出非常有用的基于反射的编程模式。
读前必备:
[.net 面向对象编程基础] (10) 类的成员(字段、属性、方法)
1.什么是.NET反射?
反射是.NET一个重要的特性,《CLR via C#》一书中对.NET反射的解释为:在我们应用程序中使用元数据来表示存储。编译程序集或模块时,编译器会创建一个类型定义表、一个字段定义表、一个方法定义表以及其它表。而我们如果想动态调用这些元数据表(或说是解析这些表),或说是为这些元数据创建一个对象模型,这个过程就是反射。
简单通俗的说,就是动态调用编译过的程序集中的属性,字段,方法等的过程,就是反射。
反射在.NET,通过System.Reflection命名空间中的类来实现。
2.反射能为我们做些什么?
这个问题是我们学习反射的重点,总得知道学习它的好处,才会继续把本文看下去。
反射特性,确实是.NET一个非常重要且有用的特性。
A.枚举类型成员
B.实例化新对象
C.执行对象成员
D.查找类型信息
E.查询程序集信息
F.检查应用于某种类型的自定义特性
G.创建和编译新的程序集
H.简化执行时而非编译时绑定的数据的操作。(C# 4.0以后新功能)
此外.NET新版本中允许泛型上的反射.
以上是反射的基本特性,参考了《C#本质论》和《C#高级编程》
基于上面的基本特性,我们可以设计出很多非常实用的编程模式。
下面列举几种基于反射设计模式下的实例:
A.利用反射创动态创建程序集的API文档。基于反射允许枚举程序集中类型及成员的特性,我们可以通过反射获取已编译的程序集中的字段方法属性事件和他们的XML注释。从而动态创建程序集的API文档;
B.非常常用的反射工厂模式。反射工厂模式在设计模式中比较容易理解,也比较简单。很多代码生成器中就利用这种设计模式完成不同数据库的反射调用。比如我们有MsSql、MySql、Oracle这三种数据库,在项目设计中,我们有可能随时换另一种数据库(当然这只是假设),因此需要同时实现这三种数据库的基础增删改查的类即数据访问类。我们要切换数据库的时候,只需要在config中更改数据库类型,其他的工作交给反射工厂类去动态调用编译好的程序集中对应的数据库访问方法。
如果没有理解也没关系,这里只是说明一下反射的应用实例,以便于更有信心的学习反射。反射在设计模式中的应还有很多,这里不再列举。
3.反射应用基础
上面说了这么多,无非就是先让我们理解反射能为我们做些什么,下面进入正题,说一下反射的代码实现。
下面主要介绍反射的核心类及类成员
反射的命名空间:System.Reflection
反射的类大多都在这个命名空间中。
主要的类: System.Type
这个类是反射的核心,其属性方法可以得到运行时的信息。
Type类派生于System.Reflection.MemberInfo抽象类
|
MemberInfo类中的只读属性 |
||
|
属性 |
描述 |
备注 |
|
Type DeclaringType |
获取声明该成员的类或接口的类型 |
|
|
MemberTypes MemberType |
获取成员的类型,这个值用于指示该成员是字段、方法、属性、事件、或构造函数 |
这是一个枚举,它定义了用于表示不同成员的类型值。这些值包括:MemberTypes.Constructor, MemberTypes.Method, MemberTypes.Field, MemberTypes.Event, MemberTypes.Property。因此可以通过检查MemberType属性来确定成员的类型,例如,在MemberType属性的值为MemberTypes.Method时,该成员为方法 |
|
Int MetadataToken |
获取与特定元数据相关的值 |
|
|
Module Module |
获取一个代表反射类型所在模块(可执行文件)的Module对象 |
|
|
String Name |
成员的名称 |
|
|
Type ReflectedType |
反射的对象类型 |
|
|
Type类的只读属性 |
|
|
属性 |
描述 |
|
Assembly Assembly |
获取指定类型的程序集 |
|
TypeAttributes Attributes |
获取制定类型的特性 |
|
Type BaseType |
获取指定类型的直接基类型 |
|
String FullName |
获取指定类型的全名 |
|
bool IsAbstract |
如果指定类型是抽象类型,返回true |
|
bool IsClass |
如果指定类型是类,返回true |
|
string Namespace |
获取指定类型的命名空间 |
|
Type类的方法 |
|
|
方法 |
描述 |
|
ConstructorInfo[] GetConstructors() |
获取指定类型的构造函数列表 |
|
EventInfo[] GetEvents(); |
获取指定类型的时间列 |
|
FieldInfo[] GetFields(); |
获取指定类型的字段列 |
|
Type[] GetGenericArguments(); |
获取与已构造的泛型类型绑定的类型参数列表,如果指定类型的泛型类型定义,则获得类型形参。对于正早构造的类型,该列表就可能同时包含类型实参和类型形 |
|
MethodInfo[] GetMethods(); |
获取指定类型的方法列表 |
|
PropertyInfo[] GetProperties(); |
获取指定类型的属性列表e |
|
MemberInfo[] GetMembers(); |
获取指定类型的成员列表 |
反射还有很多类,这里不一一介绍,详细可以查阅MSDN:
https://msdn.microsoft.com/zh-cn/library/system.reflection.aspx
4.反射实例
下面通过一个实例来学习一下反射最基本的使用方法。
建立一个解决方案,包含两个项目,项目ClassLibrary生成一个DLL(包含两个类),另一个项目是ReflectionTestGet,用于反射调用类ClassLibrary

第一个项目的两个类如下:
MartialArtsMaster.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ClassLibrary
{
/// <summary>
/// 类:武林高手
/// MartialArtsMaster
/// </summary>
class MartialArtsMaster
{
/// <summary>
/// 级别
/// </summary>
public int _level = ;
/// <summary>
/// 编号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
/// <summary>
/// 门派
/// </summary>
public string Menpai { get; set; }
/// <summary>
/// 武学
/// </summary>
public string Kungfu { get; set; }
/// <summary>
/// 级别
/// </summary>
public int Level
{
get
{
return _level;
} set
{
_level = value;
}
} /// <summary>
/// 攻击
/// </summary>
/// <param name="kungfu"></param>
/// <returns></returns>
public string Attack(string kungfu)
{
return "使用用了功夫:" + kungfu;
} public string Kill(string kungfu, string name)
{
return "使用用了功夫:" + kungfu + "击杀了" + name;
}
}
}
Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ClassLibrary
{
/// <summary>
/// 类:人
/// </summary>
class Person
{
public string gender { get; set; }
public string race { get; set; }
public string Country { get; set; }
public string Eat(string strCountry)
{
switch (strCountry)
{
case "美国": return "爱吃西餐"; case "韩国": return "爱吃泡菜";
default:
return "不知道";
}
}
}
}
第二个项目调用如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection; namespace ReflectionTestGet
{
class Program
{
static void Main(string[] args)
{ Assembly asm = Assembly.LoadFrom("ClassLibrary.dll"); //加载指定的程序集
Type[] alltype = asm.GetTypes(); //获取程序集中的所有类型列表
foreach (Type calssName in alltype)
{
Console.WriteLine("加载程序的集类名:"+ calssName.Name); //打印出程序集所有类
foreach (var field in calssName.GetFields())
Console.WriteLine(calssName.Name+"字段有:" + field.Name); //打印出程序集所有字段,注意只能获取公有字段
foreach (var pro in calssName.GetProperties())
Console.WriteLine(calssName.Name + "属性有:" + pro.Name); //打印出程序集所有属性
foreach (var met in calssName.GetMethods())
Console.WriteLine(calssName.Name + "方法有:" + met.Name); //打印出程序集所有方法 }
Console.ReadKey();
}
}
}
运行结果如下:

5.本节要点:
本节主要介绍和反射的用途及反射的基本操作类及属性方法,下节继续深入介绍如何将反射技术应用于实际项目之中。
==============================================================================================
<如果对你有帮助,记得点一下推荐哦,如有
有不明白或错误之处,请多交流>
<对本系列文章阅读有困难的朋友,请先看《.net 面向对象编程基础》>
<转载声明:技术需要共享精神,欢迎转载本博客中的文章,但请注明版权及URL>
.NET 技术交流群:467189533 
==============================================================================================
[.net 面向对象程序设计进阶] (20) 反射(Reflection)(上)利用反射技术实现动态编程的更多相关文章
- [.net 面向对象程序设计进阶] (16) 多线程(Multithreading)(一) 利用多线程提高程序性能(上)
[.net 面向对象程序设计进阶] (16) 多线程(Multithreading)(一) 利用多线程提高程序性能(上) 本节导读: 随着硬件和网络的高速发展,为多线程(Multithreading) ...
- [.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(三) 利用多线程提高程序性能(下)
[.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(二) 利用多线程提高程序性能(下) 本节导读: 上节说了线程同步中使用线程锁和线程通知的方式来处理资源共享问题,这 ...
- [.net 面向对象程序设计进阶] (15) 缓存(Cache)(二) 利用缓存提升程序性能
[.net 面向对象程序设计进阶] (15) 缓存(Cache)(二) 利用缓存提升程序性能 本节导读: 上节说了缓存是以空间来换取时间的技术,介绍了客户端缓存和两种常用服务器缓布,本节主要介绍一种. ...
- [.net 面向对象程序设计进阶] (14) 缓存(Cache) (一) 认识缓存技术
[.net 面向对象程序设计进阶] (14) 缓存(Cache)(一) 认识缓存技术 本节导读: 缓存(Cache)是一种用空间换时间的技术,在.NET程序设计中合理利用,可以极大的提高程序的运行效率 ...
- [.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 利用多线程提高程序性能(中)
[.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 利用多线程提高程序性能(中) 本节要点: 上节介绍了多线程的基本使用方法和基本应用示例,本节深入介绍.NET ...
- [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦
[.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...
- [.net 面向对象程序设计进阶] (1) 开篇
[.net 面向对象程序设计进阶] (1) 开篇 上一系列文章<.net 面向对象编程基础>写完后,很多小伙伴们希望我有时间再写一点进阶的文章,于是有了这个系列文章.这一系列的文章中, 对 ...
- [.net 面向对象程序设计进阶] (23) 团队开发利器(二)优秀的版本控制工具SVN(上)
[.net 面向对象程序设计进阶] (23) 团队开发利器(二)优秀的版本控制工具SVN(上) 本篇导读: 上篇介绍了常用的代码管理工具VSS,看了一下评论,很多同学深恶痛绝,有的甚至因为公司使用VS ...
- [.net 面向对象程序设计进阶] (24) 团队开发利器(三)使用SVN多分支并行开发(下)
[.net 面向对象程序设计进阶] (24) 团队开发利器(三)使用SVN多分支并行开发(下) 本篇导读: 接上篇继续介绍SVN的高级功能,即使用分支并行开发.随着需求的不断变更,新功能的增加.特别是 ...
随机推荐
- string与int互换
1:将string转化为int 1.) int i = Integer.parseInt(String s); 2.) int i = Integer.valueOf(my_str).intValue ...
- spring-data-redis 用法
- Copy-On-Write容器
Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...
- RQNOJ 490 环形石子合并
题目链接:https://www.rqnoj.cn/problem/490 题目描述 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一 ...
- wpf,能够复制文字 及自动识别URL超链接的TextBlock
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using S ...
- java常用设计模式
一个程序员对设计模式的理解: "不懂"为什么要把很简单的东西搞得那么复杂. 后来随着软件开发经验的增加才开始明白我所看到的"复杂"恰恰就是设计模式的精髓所在,我 ...
- 北京电子科技学院(BESTI)实验报告5
北京电子科技学院(BESTI)实验报告5 课程: 信息安全系统设计基础 班级:1452.1453 姓名:(按贡献大小排名) 郑凯杰.周恩德 学号:(按贡献大小排名) 20145314.20145217 ...
- SpringMvc的简单介绍
1.mcv框架要做哪些事情 (a)将url映射到java类或者Java类的方法 (b)封装用户提交的数据 (c)处理请求---调用相关的业务处理,封装响应的数据 (d)将封装的数据进行渲染,jsp,h ...
- 【翻译svg教程 】svg 的坐标系统
http://tutorials.jenkov.com/svg/svg-coordinate-system.html svg的坐标系统(和大多数计算机绘图的坐标系统)和数学中绘图系统有点不一样 数学/ ...
- 图解修改mysql的默认数据库存放目录
按照下图三步完成: