反射
在运行过程中,检查和处理 程序元素。例如:
- 枚举 类型的 成员
- 实例化 新对象
- 执行 对象的 成员
- 查找 类型的 信息
- 查找 程序集的 信息
- 检查 应用于某种类型的 自定义特性
- 创建和编译 新程序集
System.Type 类
System.Type可以用于 访问 任何数据类型 的信息
Type类 是一个抽象的基类- 实例化一个
Type对象,实际上是实例化了Type的一个派生类 - 一般情况下,派生类只提供各种
Type类中方法和属性的 override,而不添加新的方法和属性
- 实例化一个
- 获得
Type引用的 3 种方式:typeof运算符- 参数是 类型的名称
- 类型名称 不放在引号中
- 在一个 变量 上调用
GetType()方法- 所有的 类 都会从
System.Object继承 这个方法 - 对于此情况非常有用: 已知一个变量,但不确定 其类型 的情况
- 返回的
Type引用 只包含 该数据类型 的信息,而不包含 该类型的实例 的任何信息
- 所有的 类 都会从
Type类的静态方法GetType()方法
Type类是 许多反射功能 的入口Type类 可用的属性 都是只读的- 不能用于修改类型
Type t = typeof(double);
Console.WriteLine(vecType.IsClass); //true
double d = 10;
Type t = d.GetType();
Type t = Type.GetType("System.Double");
Type类的属性
Type 类有很多属性,分为 3 类:
- 获取 与数据类型 相关的 各种名称的 字符串,e.g.
Name数据类型 名FullName数据类型 的完全限定名 (包括 名称空间)Namespace定义 数据类型的 名称空间
- 进一步 获取
Type对象的 引用,这些 引用 表示 数据类型 相关的类。 e.g.BaseType数据类型的 直接 基类UnderlyingSystemType数据类型 在.NET运行库中 映射到的 类型 (IL识别的特定预定义类型)
- 布尔类型的属性
IsAbstractIsArrayIsClassIsEnumIsInterfaceIsPointerIsPremitive(是不是 预定义的 基元数据类型)IsPublicIsSealedIsValueType
通过 Type 得到 Assembly
得到 定义该 数据类型 的 程序集 的引用
Type t = typeof(Vector);
Assembly containingAssembly = new Assembly(t);
Type 类的方法
大多数 方法 用于 获取 数据类型 的成员(构造函数、属性、方法、事件等)的信息
- GetMethod() 返回 一个 System.Reflection.MethodInfo 的引用
- GetMethods() 返回 MethodInfo 的数组。是所有方法的信息
GetMethod() 和 GetMethods() 的重载方法中,有一个参数BindingFlags枚举值,表示返回哪些成员
- 公有成员
- 实例成员
- 静态成员
- GetConstructor() 返回 ConstructorInfo
- GetConstructors()
- GetEvent() 返回 EventInfo
- GetEvents()
- GetField() 返回 FieldInfo
- GetFields()
- GetMember() 返回 MemberInfo
- GetMembers() 返回 所有成员的信息,包括构造函数、属性、方法等等
- GetDefaultMembers()
- GetMethod() 返回 MethodInfo
- GetMethods()
- GetProperty() 返回 PropertyInfo
- GetProperties()
示例
- 成员的 DeclaringType
- 就是指 声明这个成员的类的名称
- 如果成员 继承自 基类,则返回基类的名称
- 如果成员是方法,用MemberInfo 可以获得成员的名字,也就是方法名,但是无法获得方法的签名。
- 要获得签名,需要其他对象
using System;
using System.Reflection;
using System.Text;
namespace TypeView
{
class Program
{
private static StringBuilder OutputText = new StringBuilder();
static void Main()
{
// modify this line to retrieve details of any other data type
Type t = typeof(double);
AnalyzeType(t);
Console.WriteLine($"Analysis of type {t.Name}");
Console.WriteLine(OutputText.ToString());
Console.ReadLine();
}
static void AnalyzeType(Type t)
{
TypeInfo typeInfo = t.GetTypeInfo();
AddToOutput($"Type Name: {t.Name}");
AddToOutput($"Full Name: {t.FullName}");
AddToOutput($"Namespace: {t.Namespace}");
Type tBase = typeInfo.BaseType;
if (tBase != null)
{
AddToOutput($"Base Type: {tBase.Name}");
}
AddToOutput("\npublic members:");
foreach (MemberInfo member in t.GetMembers())
{
AddToOutput($"{member.DeclaringType} {member.MemberType} {member.Name}");
}
}
static void AddToOutput(string Text) =>
OutputText.Append($"{Environment.NewLine} {Text}");
}
}
Analysis of type Double
Type Name: Double
Full Name: System.Double
Namespace: System
Base Type: ValueType
public members:
System.Double Method IsFinite
System.Double Method IsInfinity
System.Double Method IsNaN
System.Double Method IsNegative
System.Double Method IsNegativeInfinity
System.Double Method IsNormal
System.Double Method IsPositiveInfinity
System.Double Method IsSubnormal
System.Double Method CompareTo
System.Double Method CompareTo
System.Double Method Equals
System.Double Method op_Equality
System.Double Method op_Inequality
System.Double Method op_LessThan
System.Double Method op_GreaterThan
System.Double Method op_LessThanOrEqual
System.Double Method op_GreaterThanOrEqual
System.Double Method Equals
System.Double Method GetHashCode
System.Double Method ToString
System.Double Method ToString
System.Double Method ToString
System.Double Method ToString
System.Double Method TryFormat
System.Double Method Parse
System.Double Method Parse
System.Double Method Parse
System.Double Method Parse
System.Double Method Parse
System.Double Method TryParse
System.Double Method TryParse
System.Double Method TryParse
System.Double Method TryParse
System.Double Method GetTypeCode
System.Object Method GetType
System.Double Field MinValue
System.Double Field MaxValue
System.Double Field Epsilon
System.Double Field NegativeInfinity
System.Double Field PositiveInfinity
System.Double Field NaN
System.Reflection.Assembly 类
System.Reflection.Assembly可以用于 访问 给定程序集 的元数据 或者 把这个程序集加载到程序中
使用
Assembly实例前, 需要把相应的程序集 加载到 正在运行的 进程中。可以使用:
- 静态方法
Assembly.Load():- 参数是 程序集 的 名称
- 运行库 会在各个位置上搜索 该程序集,包括:
- 本地目录
- 全局程序集缓存
- 静态方法
Assembly.LoadFrom()- 参数是 程序集 的 完整路径名
- 不会在其他位置搜索该程序集
- 这两个方法 有很多 重载。它们提供了其他安全信息
加载了一个程序集后,就可以使用它的各种属性 进行查询
string name = assembly1.FullName;
Assembly.ExportedTypes属性:返回程序集中定义的所有类型
- 获取 程序集中定义的 类型
Assembly.GetTypes()返回一个Type数组
- 获取 程序集或类型中定义的 自定义特性
- 程序集从整体上关联了什么自定义特性, 可以调用
Attribute类的一个静态方法GetCustomAttributes()。它有很多重载: - 重载1:
- 参数:
- 程序集的引用
- 返回 这个程序集 所有自定义特性。
Attribute数组
Attribute[] definedAttributes = Attribute.GetCustomAttributes(assembly1); - 参数:
- 重载2:
- 参数:
- 程序集的引用
- 一个类的
Type的引用
- 返回 这个类的所有自定义特性。
Attribute数组
- 参数:
- 程序集从整体上关联了什么自定义特性, 可以调用
GetCustomAttribute():- 参数:
- 一个
Type引用。是关心的自定义特性的类的Type引用
- 一个
- 返回 自定义
Attribute。而不是基类Attribute。用起来 不用再做显式转换
Assembly theAssembly = Assembly.Load(new AssemblyName("VectorClass")); Attribute supportsAttribute = theAssembly.GetCustomAttribute(typeof(SupportsWhatsNewAttribute));- 参数:
- 要获得 方法 构造函数 字段等的自定义特性,需要调用
MethodInfoConstructorInfoFieldInfo的GetCustomAttributes()方法
为什么 要费尽周折 为自定义特性 编写类?
自定义特性 确实 和对象一样,加载了程序集之后,就可以读取 这些特性对象,查看它们的属性、调用它们的方法