最近老是碰到反射的问题,把几篇文章转贴过来,进行整合,希望对后来的有所帮助
反射的概述 
  反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等,。System.reflection命名空间包含的几个类,允许你反射(解析)这些元数据表的代码
  和反射相关的命名空间(我们就是通过这几个命名空间访问反射信息):   
  System.Reflection.MemberInfo   
   System.Reflection.EventInfo   
   System.Reflection.FieldInfo  
   System.Reflection.MethodBase   
   System.Reflection.ConstructorInfo   
   System.Reflection.MethodInfo   
   System.Reflection.PropertyInfo   
   System.Type   
   System.Reflection.Assembly   
  反射的层次模型:   
  
  注:层次间都是一对多的关系   
  反射的作用:   
  1. 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现 有对象中获取类型  
  2. 应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。   
  3. 反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。   
  应用要点:   
  1. 现实应用程序中很少有应用程序需要使用反射类型  
  2. 使用反射动态绑定需要牺牲性能   
  3. 有些元数据信息是不能通过反射获取的   
  4. 某些反射类型是专门为那些clr 开发编译器的开发使用的,所以你要意识到不是所有的反射类型都是适合每个人的。
   
  反射appDomain 的程序集   
   当你需要反射AppDomain 中包含的所有程序集,示例如下:
   static void Main   
   {   
   //通过GetAssemblies 调用appDomain的所有程序集   
  foreach (Assembly assem in Appdomain.currentDomain.GetAssemblies())   
  {   
   //反射当前程序集的信息   
   reflector.ReflectOnAssembly(assem)   
  }   
  }
  
  说明:调用AppDomain 对象的GetAssemblies 方法 将返回一个由System.Reflection.Assembly元素组成的数组。   
  反射单个程序集   
  上面的方法讲的是反射AppDomain的所有程序集,我们可以显示的调用其中的一个程序集,system.reflecton.assembly 类型提供了下面三种方法:   
  1. Load 方法:极力推荐的一种方法,Load 方法带有一个程序集标志并载入它,Load 将引起CLR把策略应用到程序集上,先后在全局程序集缓冲区,应用程序基目录和私有路径下面查找该程序集,如果找不到该程序集系统抛出异常  
  2. LoadFrom 方法:传递一个程序集文件的路径名(包括扩展名),CLR会载入您指定的这个程序集,传递的这个参数不能包含任何关于版本号的信息,区域性,和公钥信息,如果在指定路径找不到程序集抛出异常。  
  3. LoadWithPartialName:永远不要使用这个方法,因为应用程序不能确定再在载入的程序集的版本。该方法的唯一用途是帮助那些在.Net框架的测试环节使用.net 框架提供的某种行为的客户,这个方法将最终被抛弃不用。   
  注意:system.AppDomain 也提供了一种Load 方法,他和Assembly的静态Load 方法不一样,AppDomain的load 方法是一种实例方法,返回的是一个对程序集的引用,Assembly的静态Load 方发将程序集按值封装发回给发出调用的AppDomain.尽量避免使用AppDomain的load 方法     
  利用反射获取类型信息   
  前面讲完了关于程序集的反射,下面在讲一下反射层次模型中的第三个层次,类型反射   
  一个简单的利用反射获取类型信息的例子:   
  using system;   
  using sytem.reflection;   
  class reflecting   
  {   
   static void Main(string[]args)   
  {   
   reflecting reflect=new reflecting();//定义一个新的自身类   
   //调用一个reflecting.exe程序集   
   assembly myAssembly =assembly.loadfrom(“reflecting.exe”)   
   reflect.getreflectioninfo(myAssembly);//获取反射信息   
  }  
  //定义一个获取反射内容的方法   
  void getreflectioninfo(assembly myassembly)   
  {   
   type[] typearr=myassemby.Gettypes();//获取类型   
   foreach (type type in typearr)//针对每个类型获取详细信息  
   {   
   //获取类型的结构信息   
   constructorinfo[] myconstructors=type.GetConstructors;   
   //获取类型的字段信息  
   fieldinfo[] myfields=type.GetFiedls()   
   //获取方法信息   
   MethodInfo myMethodInfo=type.GetMethods();   
   //获取属性信息   
   propertyInfo[] myproperties=type.GetProperties   
   //获取事件信息   
   EventInfo[] Myevents=type.GetEvents;  
  }   
  }   
  }
  
  其它几种获取type对象的方法:   
  1. System.type 参数为字符串类型,该字符串必须指定类型的完整名称(包括其命名空间)   
  2. System.type 提供了两个实例方法:GetNestedType,GetNestedTypes   
  3. Syetem.Reflection.Assembly 类型提供的实例方法是:GetType,GetTypes,GetExporedTypes  
  4. System.Reflection.Moudle 提供了这些实例方法:GetType,GetTypes,FindTypes   
  设置反射类型的成员
  
   反射类型的成员就是反射层次模型中最下面的一层数据。我们可以通过type对象的GetMembers 方法取得一个类型的成员。如果我们使用的是不带参数的GetMembers,它只返回该类型的公共定义的静态变量和实例成员,我们也可以通过使用带参数的GetMembers通过参数设置来返回指定的类型成员。具体参数参考msdn 中system.reflection.bindingflags 枚举类型的详细说明。
  
  例如:
  
  
  
  //设置需要返回的类型的成员内容
  
  bindingFlags bf=bingdingFlags.DeclaredOnly|bingdingFlags.Nonpublic|BingdingFlags.Public; 
  foreach (MemberInfo mi int t.getmembers(bf))   
  {   
   writeline(mi.membertype) //输出指定的类型成员   
  }   
  通过反射创建类型的实例  
  通过反射可以获取程序集的类型,我们就可以根据获得的程序集类型来创建该类型新的实例,这也是前面提到的在运行时创建对象实现晚绑定的功能  
  我们可以通过下面的几个方法实现: 
  1. System.Activator 的CreateInstance方法。该方法返回新对象的引用。具体使用方法参见msnd  
  2. System.Activator 的createInstanceFrom 与上一个方法类似,不过需要指定类型及其程序集   
  3. System.Appdomain 的方法:createInstance,CreateInstanceAndUnwrap,CreateInstranceFrom和CreateInstraceFromAndUnwrap   
  4. System.type的InvokeMember实例方法:这个方法返回一个与传入参数相符的构造函数,并构造该类型。   
  5. System.reflection.constructinfo 的Invoke实例方法   
  反射类型的接口   
  如果你想要获得一个类型继承的所有接口集合,可以调用Type的FindInterfaces GetInterface或者GetInterfaces。所有这些方法只能返回该类型直接继承的接口,他们不会返回从一个接口继承下来的接口。要想返回接口的基础接口必须再次调用上述方法。   
  反射的性能:   
  使用反射来调用类型或者触发方法,或者访问一个字段或者属性时clr 需 要做更多的工作:校验参数,检查权限等等,所以速度是非常慢的。所以尽量不要使用反射进行编程,对于打算编写一个动态构造类型(晚绑定)的应用程序,可以采取以下的几种方式进行代替:   
  1. 通过类的继承关系。让该类型从一个编译时可知的基础类型派生出来,在运行时生成该类 型的一个实例,将对其的引用放到其基础类型的一个变量中,然后调用该基础类型的虚方法。   
  2. 通过接口实现。在运行时,构建该类型的一个实例,将对其的引用放到其接口类型的一个变量中,然后调用该接口定义的虚方法。   
  3.通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些
1 反射技术与设计模式 
        反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等。还可以获得每个成员的名称、限定符和参数等。有了反射,即可对每一个类型了如指掌。如果获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道。

1.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命名空间中的类通过序列化来间接地使用反射。

1.2 反射技术示例 
        下面是反射技术的示例,我们可以在程序去得时动态实例化对象,获得对象的属性,并调用对象的方法。
 1Namespace ReflectionExample
 2{
 3  class Class1
 4  {
 5      [STAThread]
 6      static void Main (string [ ] args)
 7      {
 8          System.Console.WriteLine(“列出程序集中的所有类型”);
 9          Assembly a = Assembly.LoadFrom (“ReflectionExample.exe”);
10          Type[ ] mytypes = a.GetTypes( );
11
12          Foreach (Type t in mytypes)
13          {
14              System.Console.WriteLine ( t.Name );
15          }

16          System.Console.ReadLine ( );
17      System.Console.WriteLine (“列出HellWord中的所有方法” );
18      Type ht = typeof(HelloWorld);
19      MethodInfo[] mif = ht.GetMethods();
20      foreach(MethodInfo mf in mif)
21      {
22          System.Console.WriteLine(mf.Name);
23      }

24      System.Console.ReadLine();
25      System.Console.WriteLine("实例化HelloWorld,并调用SayHello方法");
26      Object obj = Activator.CreateInstance(ht);
27      string[] s = {"zhenlei"};
28      Object bojName = Activator.CreateInstance(ht,s);
29      BindingFlags flags = (BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Static|BindingFlags.Instance|BindingFlags.DeclaredOnly);
30      MethodInfo msayhello = ht.GetMethod("SayHello");
31      msayhello.Invoke(obj,null);
32      msayhello.Invoke(objName,null);
33      System.Console.ReadLine();
34    }

35    }

36}

 1using System;
 2namespace ReflectionExample
 3{
 4    public class HelloWorld
 5    {
 6        string myName = null;
 7        public HelloWorld(string name)
 8        {
 9            myName = name;
10        }

11        public HelloWorld() : this(null)
12        {}
13        public string Name
14        {
15            get
16            {
17                return myName;
18            }

19        }

20        public void SayHello()
21        {
22            if(myName == null)
23            {
24                System.Console.WriteLine("Hello World");
25            }

26            else
27            {
28                System.Console.WriteLine("Hello," + myName);
29            }

30        }

31    }

32}

33

1.3 在设计模式实现中使用反射技术 
        采用反射技术可以简化工厂的实现。
(1)工厂方法:通过反射可以将需要实现的子类名称传递给工厂方法,这样无须在子类中实现类的实例化。
(2)抽象工厂:使用反射可以减少抽象工厂的子类。 
        采用反射技术可以简化工厂代码的复杂程度,在.NET项目中,采用反射技术的工厂已经基本代替了工厂方法。 
        采用反射技术可以极大地简化对象的生成,对以下设计模式的实现也有很大影响。
(1)命令模式:可以采用命令的类型名称作为参数直接获得命令的实例,并且可以动态执行命令。
(2)享元模式:采用反射技术实例化享元可以简化享元工厂。

2 委托技术与设计模式
        委托技术是.NET引入的一种重要技术,使用委托可以实现对象行为的动态绑定,从而提高设计的灵活性。

2.1 .NET中的委托技术
        .NET运行库支持称为“委托”的引用类型,其作用类似于C++中的函数指针。与函数指针不同,委托实例独立于其封装方法的类,主要是那些方法与委托类型兼容。另外,函数指针只能引用静态函数,而委托可以引用静态和实例方法。委托主要用于.NET Framework中的事件处理程序和回调函数。
        所有委托都从System.Delegate继承而来并且有一个调用列表,这是在调用委托时所执行方法的一个链接列表。产生的委托可以用匹配的签名引用任何方法,没有为具有返回类型并在调用列表中包含多个方法的委托定义返回值。
        可以使用的委托Cimbine及Remove方法在其调用列表中添加和移除方法。若要调用委托,可使用Invoke方法,或者使用BeginInvoke和EndInvoke方法异步调用委托。委托类的实现由运行库提供,而不由用户代码提供。
        委托适用于那种在某些语言中需要用函数指针来解决的情况,但是与函数指针不同,它是面向对象和类型安全的。
        委托声明定义一个类,它是从System.Delegate类派生的类。委托实例封装了一个调用列表,其中列出了一个或多个方法,每个方法称为一个可调用实体。对于实例方法,可调用实体由一个实例和该实例的方法组成;对于静态方法,可调用实体仅由一个方法组成。如果用一组合适的参数来调用一个委托实例,则该委托实例所封装的每个可调用实体都会被调用,并且使用上述同一组参数。
        委托实例的一个有用的属性是它既不知道,也不关心其封装方法所属类的详细信息,对它来说最重要的是这些方法与该委托的类型兼容。即只要方法的返回类型和参数表是相同的,则方法与委托类型兼容,方法的名称不一定要与委托类相同。
定义和使用委托分为声明、实例化和调用3个步骤。委托用委托声明语法声明,如:
    delegate void myDelegate( );
声明一个名为myDelegate的委托,它不带参数并且不返回任何结果,如:
class Test
{
       static void F( ) 
      {
              System.Console.WriteLine (“Test.F”);
      }
       static void Main ( )  
      {
            myeDelegate d = new myDelegate (F);
            d ( );
      }
}
创建一个myDelegate实例,然后立即调用它。这样做并没有太大的意义,因为直接调用方法会更简单。当涉及其匿名特性时,委托才能真正显示出其效果,如:
    void MultiCall (myDelegate d, int count )  {
      for  (int I = 0; I < count; I++)  {
        d( );
      }
    }
显示一个重复调用 myDelegate的MultiCall 方法,这个方法不知道,也不必知道myDelegate的目标方法的类型、该方法具有的可访问性或者是否为静态。对它来说最重要的是目标方法与myDelegate兼容。

2.2示例
        下面的例子说明了委托的实现,代码如下:
 1using System;
 2namespace DelegateExample
 3{
 4    public class TemplateMethod
 5    {
 6        public delegate float Comp(float a,float b);
 7        public Comp myComp;
 8        public TemplateMethod()
 9        {}
10        public float DoComp(float[] f)
11        {
12            float nf = float.NaN;
13            foreach(float df in f)
14            {
15                if(float.IsNaN(nf))
16                    nf = df;
17                else
18                    nf = myComp(nf,df);
19            }

20            return nf;
21        }

22
23    }

24}

2.3 委托技术与GOF设计模式中委托的关系
        需要指出的是,.NET中的委托技术与GOF在《设计模式》中所提列的委托的意图一致,但在实现方法上有相当大的区别。.NET中的委托更进一步地降低了对象间的耦合性,将静态的组合关系变为运行时的动态组合关系。
        GOF在《设计模式》中定义的委托是:“委托是一种组合方法,它使组合具有与继承同样的复用能力。在委托方式下,有两个对象参与处理一个请求,接受请求的对象将操作委托给它的代理者(delegate),它类似于子类将请求交给它的父类处理。使用继承时,被继承的操作总能引用接受请求的对象。在C++中通过this成员变量,在Smalltalk中则通过self。委托方式为了得到同样的效果,接受请求的对象将自身传给被委托者(代理人),使被委托的操作可以引用接受请求的对象。”
        如果采用.NET的委托技术,上述结构可以更加灵活。Window不引用Rectangle即可实现Area的计算,为此首先声明一个计算面积的委托定义,示例代码如下:
    public delegate float Darea();
然而在Window类中声明与这个代理一致的接口:
    class Window
    { 
        public Darea Area;
    }
这里不需要引用Rectangle类,只是在执行时动态绑定即可:
Rectangle rc = new Rectangle();
Window w = new Window();
w.Area = new Darea(rc.Area);
        这样当调用w的Area时,实际调用的是Reactangel的Area方法。从实现意图上看,.NET的委托更好地实现了GOF所阐述的意图,结构上也更为灵活。但这两种委托解决的不是一个层面的问题,GOF的委托强调的是一种策略,而.NET和委托技术则是具体实现。

2.4 委托技术与设计模式实现
        采用委托技术可以进一步实现用组合代替继承的思路,很多采用继承实现的关系可以采用委托实现。采用委托可以简化下列设计模式的使用。
(1)模板方法:这种方法采用继承实现具体方法,采用委托可以动态实现方法的组合。
(2)观察者:可以使用事件委托实现观察者与主题之间的通信。
(3)中介者:使用委托可以去除工件与中介者之间的耦合关系。