第23章 程序集加载和反射
23.1 程序集加载
CLR使用System.Reflection.Assembly类的静态方法Load来尝试加载程序集。
Load导致CLR向程序集应用一个版本绑定重定向策略,并在GAC(全局程序集缓存)中查找程序集。如果没找到,就接着去应用程序的基目录、私有路径子目录和codebase位置查找。
<?xml version="1.0" encoding="utf-8" ?>
<!--App.config-->
<configuration>
<runtime>
<assemblyBinding>
<assemblyIdentity name="***" />
<bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
<codeBase version="2.0.0.0" href="http://www.wintellect.com"/>
</assemblyBinding>
</runtime>
</configuration>
23.3 反射的性能
反射会造成编译时无法保证类型安全性。由于反射要严重依赖字符串,所以会丧失编译时的类型安全性。
反射速度慢。
23.3.2 类型对象的准确含义
System.Type类型是执行类型和对象的起点。System.Type是一个从System.Reflection.MemberInfo派生的抽象基类。
23.3.4 构造类型的实例
1). System.Activator的CreateInstance方法
2). System.Activator的CreateInstanceFrom方法
3). System.AppDomain的方法
4). System.Type的InvokeMember实例方法
5). System.Reflection.ConstructorInfo的Invoke实例方法
创建数组类型实例应该调用Array的静态CreateInstance方法。
创建委托实例,应该调用Delegate的静态CreateDelegate方法。
创建泛型类型实例,应该首先要获取对开放类型的一个引用,然后调用Type的公共实例方法MakeGenericType。
Type genericType = typeof(Dictionary<,>);
Type genericType2 = genericType.MakeGenericType(typeof(int), typeof(List<int>));
object instance = Activator.CreateInstance(genericType2);
Console.WriteLine(instance);
23.5 使用反射发现类型的成员
23.5.1 发现类型成员
FCL包含一个名为System.Reflection.MemberInfo的类型。这是一个抽象类型,封装了一组所有类型成员都通用的属性。从MemberInfo派生的一组类,每个类都封装了与一个特定类型成员相关的更多属性。
Type genericType = typeof(Class1);
foreach (var f in genericType.GetFields())
Console.WriteLine(f.Name);
foreach (var m in genericType.GetMethods())
Console.WriteLine(m.Name);
foreach (var c in genericType.GetConstructors())
Console.WriteLine(c.Name);
foreach (var p in genericType.GetProperties())
Console.WriteLine(p.Name);
foreach (var e in genericType.GetEvents())
Console.WriteLine(e.Name);
23.5.2 BindingFlags:筛选返回的成员种类
可以调用Type的GetMembers,GetNestedTypes,GetFields,GetConstructors,GetMethods,GetProperties或者GetEvents方法来查询一个类型的成员。调用上述任何一个方法时,可以传递System.Reflection.BindingFlags枚举类型的一个实例。这个枚举类型标识了一组通过逻辑OR运算合并到一起的标志(bit flag),目的是对这些方法返回的成员进行筛选。
Type genericType = typeof(Class1);
foreach (var m in genericType.GetMethods(BindingFlags.Instance|BindingFlags.Public|BindingFlags.Static))
Console.WriteLine(m.Name);
23.5.4 调用类型的成员
调用一个FieldInfo,可以获取或设置字段的值:调用一个ConstructorInfo,可以向构造器传递实参,从而构造类型的一个实例;调用一个MethodInfo,可以通过传递实例来调用方法,并获得它的返回值;调用PropertyInfo,可以调用(call)属性的get和set访问器方法;而调用一个EventInfo可以添加或删除一个事件处理程序。
Type类提供了一个InvokeMember访问,可通过它调用一个成员。