1.反射产生的背景

对无法直接添加引用的程序集中类型元素的动态获取和使用。使用场景如插件开发,vs本身的智能提示。

2.反射的基本原理

  依托于元数据,运行时动态获取并构建程序集、模块、类型及字段等目标对象并调用目标对象(如调用方法,属性赋值)的机制

元数据,就是描述数据的数据。在CLR中,元数据就是对一个模块定义或引用的所有东西的描述系统。

也就是代码架构,vs中选择一个类型,按f12转到定义。

3.反射的作用

1、查看和遍历类型(及其成员)的基本信息和程序集元数据(metadata);

2、迟绑定(Late-Binding)方法和属性。3、动态创建类型实例(并可以动态调用所创建的实例的方法、字段、属性)

4 .反射的基础--运行时类型标识

  • 运行时类型标识(RTTI),可以在程序执行期间判定对象类型。
  • 运行时类型标识,能预先测试某个强制类型转换操作,能否成功,从而避免无效的强制类型转换异常。
  • 在c#中有三个支持RTTI的关键字:is 、 as  、typeof。
  • is运算符:

    通过is运算符,能够判断对象类型是否为特顶类型,如果两种类型是相同类型或者两者之间存在引用,装箱拆箱转换,则表明两种类型是兼容的。

  • as运算符:

    在运行期间执行类型转换且能够使得类型转换失败不抛异常,而返回一个null值。

  • typeof运算符: 

     as ,is 能够测试两种类型的兼容性。但大多数情况下需要获得某个类型的具体信息就用到了typeof,它返回与具体类型相关的System.Type对象一旦获得给定类型的Type对象,就可以通过使用该对象定义的各种属性,字段,方法来获取类型的具体信息

4 .反射的核心类:System.Type

这个类封装了关于对象的信息,获得了类型的Type对象后,就可根据Type提供的属性和方法获取此类型的一切信息(方法、字段、属性、事件、参数、构造函数等)

获取Type对象有两种形式,一种是获取当前加载程序集中的类型(Runtime),一种是获取没有加载的程序集的类型。

我们先考虑Runtime时的Type,一般来说有三种获取方法:

2.1使用Type类提供的静态方法GetType()

Type t = Type.GetType("System.IO.Stream");
txtOutput.Text = t.ToString();

注意到GetType方法接受字符串形式的类型名称。

2.2 使用 typeof 操作符

// 如果在页首写入了using System.IO; 也可以直接用 typeof(Stream);
Type t = typeof(System.IO.Stream);

这时的使用有点像泛型,Stream就好像一个类型参数一样,传递到typeof操作符中。

2.3 通过类型实例获得Type对象

String name = "Jimmy Zhang";
Type t = name.GetType();

使用这种方法时应当注意,尽管我们是通过变量(实例)去获取Type对象,但是Type对象不包含关于这个特定对象的信息,仍是保存对象的类型(String)的信息。

5 .反射程序集

在.Net中,程序集是进行部署、版本控制的基本单位,它包含了相关的模块和类型,只是讲述如何通过反射获取程序集信息。

在System.Reflection命名空间下有一个Assembly类型,它代表了一个程序集并包含了关于程序集的信息。

在程序中加载程序集时,我们可以使用 Assembly类型提供的静态方法LoadFrom() 和 Load(),比如:

Assembly asm = Assembly.LoadFrom("Demo.dll");

或者

Assembly asm = Assembly.Load("Demo");

当使用LoadFrom()方法时提供的是程序集的文件名,当将一个程序集添加到项目引用中以后,可以直接写“文件名.dll”。

如果想加载一个不属于当前项目的程序集,则需要给出全路径,比如:

Assembly asm = Assembly.LoadFrom(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Web.dll");

使用Load()方法的时候,只用提供程序集名称即可,不需要后缀名。

如果想获得当前程序集,可以使用Assembly类型的静态方法 GetExecutingAssembly,它返回包含当前执行的代码的程序集(也就是当前程序集)。

Assembly as = Assembly.GetExecutingAssembly();

在获得一个Type类型实例以后,我们还可以使用该实例的Assembly属性来获得其所在的程序集:

Type t = typeof(int)
Assembly asm = t.Assembly;

一个程序集可能有多个模块(Module)组成,每个模块又可能包含很多的类型,但.Net的默认编译模式一个程序集只会包含一个模块。

    [Serializable]
class SimpleClass
{
private String _MyString;
public SimpleClass(String mystring)
{
_MyString = mystring;
} public override string ToString()
{
return _MyString;
} static void Main(string[] args)
{
Console.WriteLine("简单程序集");
Console.Read();
}
} public class AnalyseHelper
{
/// <summary>
/// 分析程序集
/// </summary>
public static void AnalyzeAssembly(Assembly assembly)
{
Console.WriteLine("程序集名字:" + assembly.FullName);
Console.WriteLine("程序集位置:" + assembly.Location);
Console.WriteLine("程序集是否在GAC中:" +
assembly.GlobalAssemblyCache.ToString());
Console.WriteLine("包含程序集的模块名" +
assembly.ManifestModule.Name);
Console.WriteLine("运行程序集需要的CLR版本:" +
assembly.ImageRuntimeVersion);
Console.WriteLine("现在开始分析程序集中的模块");
Module[] modules = assembly.GetModules();//assembly也可以直接获取所有类型调用.gettypes()
foreach (Module module in modules)
{
AnalyzeModule(module);
}
} /// <summary>
/// 分析模块
/// </summary>
public static void AnalyzeModule(Module module)
{
Console.WriteLine("模块名:" + module.Name);
Console.WriteLine("模块的UUID:" + module.ModuleVersionId);
Console.WriteLine("开始分析模块下的类型");
Type[] types = module.GetTypes();
foreach (Type type in types)
{
AnalyzeType(type);
}
} /// <summary>
/// 分析类型
/// </summary>
public static void AnalyzeType(Type type)
{
Console.WriteLine("类型名字:" + type.Name);
Console.WriteLine("类型的类别是:" + type.Attributes);
if (type.BaseType != null)
Console.WriteLine("类型的基类是:" + type.BaseType.Name);
Console.WriteLine("类型的GUID是:" + type.GUID);
//设置感兴趣的类型成员
BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
//分析成员
FieldInfo[] fields = type.GetFields(flags);
if (fields.Length > 0)
{
//Console.WriteLine("开始分析类型的成员");
foreach (FieldInfo field in fields)
{
// 分析成员
}
}
//分析包含的方法
// MethodInfo类派生于MethodBase抽象类,而MethodBase类继承了MemberInfo类
MethodInfo[] methods = type.GetMethods(flags);
if (methods.Length > 0)
{
//Console.WriteLine("开始分析类型的方法");
foreach (MethodInfo method in methods)
{
// 分析方法
}
}
//分析属性
PropertyInfo[] properties = type.GetProperties(flags);
if (properties.Length > 0)
{
//Console.WriteLine("开始分析类型的属性");
foreach (PropertyInfo property in properties)
{
// 分析属性
}
}
}
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
class Program
{
static void Main(string[] args)
{
//加载程序集
Assembly assembly = Assembly.LoadFrom(@"..\..\..\SimpleAssembly\bin\Debug\SimpleAssembly.exe");
AnalyseHelper.AnalyzeAssembly(assembly); // 创建一个程序集中的类型的对象
Console.WriteLine("利用反射创建对象");
string[] paras = { "测试一下反射效果" };
object obj = assembly.CreateInstance(assembly.GetModules()[0].GetTypes()[0].ToString(), true, BindingFlags.CreateInstance, null, paras, null, null);
Console.WriteLine(obj); Console.ReadKey();
}
}

上面代码按照 程序集->模块->类型 三个层次的顺序来动态分析一个程序集,当然还可以继续递归类型内部的成员,最后通过CreateInstance方法来动态创建了一个类型,这些都是反射经常被用来完成的功能,执行结果如下图所示:

.NET基础拾遗(5)反射1的更多相关文章

  1. .NET基础拾遗(4)委托、事件、反射与特性

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

  2. 基础拾遗------redis详解

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  3. 基础拾遗------webservice详解

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  4. 基础拾遗-----mongoDB操作

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  5. 基础拾遗----RabbitMQ(含封装类库源码)

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  6. 基础拾遗----RabbitMQ

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  7. Java基础拾遗(二)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76358523冷血之心的博客) 马上就要秋招了,新的一轮笔试面试马上 ...

  8. Java基础拾遗(一)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76358391冷血之心的博客) 马上就要秋招了,新的一轮笔试面试马上 ...

  9. C#基础知识回顾-- 反射(3)

    C#基础知识回顾-- 反射(3)   获取Type对象的构造函数: 前一篇因为篇幅问题因为篇幅太短被移除首页,反射这一块还有一篇“怎样在程序集中使用反射”, 其他没有什么可以写的了,前两篇主要是铺垫, ...

  10. C#基础知识回顾-- 反射(1)

    C#基础知识回顾-- 反射(1)   反射(reflection)是一种允许用户获得类型信息的C#特性.术语“反射”源自于它的工作方式: Type对象映射它所代表的底层对象.对Type对象进行查询可以 ...

随机推荐

  1. jQuery中DOM操作

    1 定义:jquery中对DOM的操作就是对DOM元素进行增删查改操作 2 分类:      1)DOM Core(核心):用途广泛 支持多种编程语言 2)HTML DOM:代码简短 只用于处理web ...

  2. android上line-height的问题

    关于line-height大家应该非常熟悉了吧,就是用来做垂直居中的,屡试不爽,基本上没有什么问题,但是最近一个项目,测试提了一个bug,看图吧. 从别处窃的图,这个问题只有安卓上才能复现,做了dem ...

  3. python 下的数据结构与算法---1:让一切从无关开始

    这段时间把<Data Structure and Algorithms with python>以及<Problem Solving with  Algorithms and Dat ...

  4. 将GridView中的数据导出到Excel代码与注意事项

    //gv:需要导出数据的GridView,filename:导出excel文件名 public void ExportToExcel(GridView gv, string filename) { s ...

  5. sqlserver中的序列

    序列是由用户定义的绑定到架构的对象.序列依据定义的间隔按升序或降序生成,并可配置为用尽时重新启动(循环).序列不与特定表关联.序列与表之间的关系由应用程序进行控制. 创建序列的语法: CREATE S ...

  6. javascript "非法值"检验.

    <script type="text/javascript"> function getCoord() { var x = document.getElementByI ...

  7. IIS中启用gzip压缩(网站优化)

    HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术.大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度.这一般是指WWW服务器中安装的一个功能,当有人来访问这个服务器中的 ...

  8. HTML&CSS基础学习笔记1.27-input提交数据

    提交数据 我们在表单上填的信息很多情况下需要提交到后台. <input>的[type]属性值为“submit”时,表示提交表单数据.它在页面的表现形式也是个按钮,点击该按钮,表单数据将会提 ...

  9. 深入浅出scanf、getcha、gets、cin函数

    转:问题描述一:(分析scanf()和getchar()读取字符) scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的.但是有时候却就是因为使用这些 ...

  10. 酷狗、QQ、天天动听——手机音乐播放器竞品对比

    如果说什么艺术与人们生活最贴近,那应该属音乐了,因此当代人不离身的手机里必然会有自己喜欢的音乐播放器APP存在. 在当今无论PC端还是手机端音乐播放器都越来越同质化,我们应该选择哪款手机音乐播放器?它 ...