1、.NET可执行应用程序结构
程序代码在编译后生成可执行的应用,我们首先要了解这种可执行应用程序的结构。
应用程序结构分为应用程序域—程序集—模块—类型—成员几个层次,公共语言运行库加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。
程序集包含模块,而模块包含类型,类型又包含成员,反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象或从现有对象中获取类型,然后调用类型的方法或访问其字段和属性。反射通常具有以下用途。
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
System.Reflection.Emit命名空间的类提供了一种特殊形式的反射,可以在运行时构造类型。
反射也可用于创建称为类型浏览器的应用程序,使用户能够选择类型,然后查看有关选定类型的信息。
此外,Jscript等语言编译器使用反射来构造符号表。System.Runtime.Serialization命名空间中的类使用反射来访问数据并确定要永久保存的字段,System.Runtime.Remoting命名空间中的类通过序列化来间接地使用反射。
namespace ReflectionExample
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
System.Console.WriteLine("列出程序集中的所有类型");
Assembly a = Assembly.LoadFrom("ReflectionExample.exe");
Type[] mytypes = a.GetTypes();
foreach(Type t in mytypes)
{
System.Console.WriteLine ( t.Name );
}
System.Console.ReadLine();
System.Console.WriteLine("列出HelloWorld中的所有方法");
Type ht = typeof(HelloWorld);
MethodInfo [] mif = ht.GetMethods ();
foreach(MethodInfo mf in mif)
{
System.Console.WriteLine(mf.Name);
}
System.Console.ReadLine();
System.Console.WriteLine("实例化HelloWorld,并调用SayHello方法");
Object obj = Activator.CreateInstance(ht);
string [] s = {"ZhenLei"};
Object objName = Activator.CreateInstance(ht,s);
//BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public |
// BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
MethodInfo msayhello = ht.GetMethod("SayHello");
msayhello.Invoke(obj,null);
msayhello.Invoke(objName,null);
System.Console.ReadLine();
}
}
}
using System;
namespace ReflectionExample
{
/// <summary>
/// HelloWorld 的摘要说明。
/// </summary>
public class HelloWorld
{
string myName = null;
public HelloWorld(string name)
{
myName = name;
}
public HelloWorld() : this(null)
{
}
public string Name
{
get
{return myName;}
}
public void SayHello()
{
if (myName==null)
System.Console.WriteLine ("Hello World");
else
System.Console.WriteLine("Hello," + myName);
}
}
}
</div>
3、在设计模式实现中使用反射技术
采用反射技术可以简化工厂的实现。
(1)工厂方法:通过反射可以将需要实现的子类名称传递给工厂方法,这样无须在子类中实现类的实例化。
(2)抽象工厂:使用反射可以减少抽象工厂的子类。
采用反射技术可以简化工厂代码的复杂程度,在.NET项目中,采用反射技术的工厂已经基本代替了工厂方法。
采用反射技术可以极大地简化对象的生成,对以下设计模式的实现也有很大影响。
(1)命令模式:可以采用命令的类型名称作为参数直接获得命令的实例,并且可以动态执行命令。
(2)享元模式:采用反射技术实例化享元可以简化享元工厂。
4.
反射的概述
反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等,。System.reflection命名空间包含的几个类,允许你反射(解析)这些元数据表的代码
和反射相关的命名空间(我们就是通过这几个命名空间访问反射信息):
注:层次间都是一对多的关系
反射的作用:
1.可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型
2.应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。
3.反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。
应用要点:
1.现实应用程序中很少有应用程序需要使用反射类型
2.使用反射动态绑定需要牺牲性能
3.有些元数据信息是不能通过反射获取的
4.某些反射类型是专门为那些clr开发编译器的开发使用的,所以你要意识到不是所有的反射类型都是适合每个人的。
反射appDomain的程序集
当你需要反射AppDomain中包含的所有程序集,示例如下:
说明:调用AppDomain对象的GetAssemblies方法将返回一个由System.Reflection.Assembly元素组成的数组。
反射单个程序集
上面的方法讲的是反射AppDomain的所有程序集,我们可以显示的调用其中的一个程序集,system.reflecton.assembly类型提供了下面三种方法:
1.Load方法:极力推荐的一种方法,Load方法带有一个程序集