《C#从现象到本质》读书笔记(八)第10章反射
个人感觉,反射其实就是为了能够在程序运行期间动态的加载一个外部的DLL集合,然后通过某种办法找到这个DLL集合中的某个空间下的某个类的某个成员(通过反射可以访问该类所包含的所有成员,不论成员是公有还是私有)。
在.NET中,查看和操作元数据的动作,称为反射。
通过反射我们可以:1)加载一个程序集,这称为动态加载程序集或者晚期绑定。2)获得程序集的托管模块(IL+元数据)。3)获得程序集中(托管模块中的)类型对象(通过元数据)。4)获得类型的成员和方法,反射可以访问类型所有的成员和方法,无论它们是不是私有的。
System.Type类会返回加载堆上的类型对象(包括静态成员和方法表)。
当我们要反射一个类的方法时,首先要获得它的类型对象,然后再使用GetMethods方法获得某个方法,获得方法之后,可以使用Invoke执行方法。
GetMembers方法默认只获得公开的成员,包括自己和类型所有父类的公开成员。
即使成员是私有的或受保护的,通过反射一样可以获得其值,甚至可以对其值进行修改。

1 class Program 2 { 3 static void Main() 4 { 5 var shapeList = new List<Shapes> { new Rectangle(), new Circle() }; 6 var method = typeof(Processor).GetMethod("Process"); 7 8 foreach (var shapes in shapeList) 9 { 10 //对每个shapes,获得它的类型,然后构造相应的泛型方法 11 var generateRef = method.MakeGenericMethod(shapes.GetType()); 12 13 //调用方法 14 generateRef.Invoke(new Processor(), null); 15 } 16 17 Console.ReadKey(); 18 } 19 } 20 21 class Processor 22 { 23 public void Process<T>() where T : Shapes, new() 24 { 25 var t = typeof(T); 26 t.GetMethod("Print").Invoke(new T(), null); 27 } 28 } 29 30 class Shapes 31 { 32 public void Print() 33 { 34 Console.WriteLine("我是形状"); 35 } 36 } 37 38 class Rectangle : Shapes 39 { 40 public void Print() 41 { 42 Console.WriteLine("我是长方形"); 43 } 44 } 45 46 class Circle : Shapes 47 { 48 public void Print() 49 { 50 Console.WriteLine("我是圆形"); 51 } 52 }
在很多时候反射是唯一的选择,例如晚期绑定:当需要动态加载某个程序集(而不是在程序开始时就加载),需要使用反射。如果系统需要面对的是通用的模型,此时无论是方法也好属性也罢,都是随应用场景而改变的,这种完全需呀动态绑定的场景下自然需要运用反射。
方法的调用有三种主要形式:直接调用,委托调用和反射调用。委托调用又可以分为直接创建强类型委托和使用表达式辅助创建委托两种方式。
性能比较:直接调用>委托调用>通用委托调用>表达式调用>反射调用>委托的DynamicInvoke调用。
反射在ORM中有着广泛的用途。
书中有一个简单的ORM的实现。代码也很详细。