[.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的高级功能,即使用分支并行开发.随着需求的不断变更,新功能的增加.特别是 ...
随机推荐
- 深信服务发布SSL站点
1.不能使用AD自带的HTTPS服务,需要新建一个服务,端口443 2.在“节点池”中添加内网HTTPS服务器的IP,端口443 3.在“策略”中新建一条策略,"服务"选新添加的端 ...
- Android中轻松显示Gif图片
android中现在没有直接显示gif的view,只能通过mediaplay来显示,且还常常不能正常显示出来,为此写了这个gifview,其用法和imageview一样使用方法:1-把GifView. ...
- Greenplum安装
最近需要安装Greenplum测试一些东西,在安装过程中出现了许多问题,所以在这里将安装过程整理一下,主要参考<Greenplum企业应用实践>和http://jxzhfei.blog.5 ...
- su root认证失败的解决方法
sudo passwd 输入安装密码. 输入新密码. 输入 su 即获得root权限.
- R语言内存管理
http://www.cnblogs.com/cloudtj/articles/5478281.html
- 文件处理命令:sed
使用:sed [-nefr] actionaction:-i直接修改读取的档案内容,而不是由屏幕输出,-r表示支持延伸型正则表达式的语法.动作说明:[n1[,n2]] function n1,n2表示 ...
- UITextView 点击添加文字 光标处于最后方
#import "ViewController.h" @interface ViewController ()<UITextViewDelegate> @end @im ...
- springmvc上传文件,抄别人的
SpringMVC中的文件上传 分类: SpringMVC 2012-05-17 12:55 26426人阅读 评论(13) 收藏 举报 stringuserinputclassencoding 这是 ...
- js Date学习
Date.parse()接收一个表示日期的字符串参数(参数错误时返回NaN),返回相应日期的毫秒数.(使用自 UTC(Coordinated Universal Time,国际协调时间)1970 年 ...
- maven内部运行原理解析
maven至今还是Java编程语言构建的事实标准,大部分项目还在使用maven来进行构建,因此了解maven内部运行的原理对定位和分析问题还是很有裨益的.本篇文章主要介绍一些maven内部运行过程中的 ...