反射
反射是指对程序集中的元数据(如:方法、类型、参数、字段、属性、自定义特性等)进行检查的过程。我们是通过System.Type的实例来访问类型的元数据。
使用System.Type访问元数据
读取类型的元数据,首先要获得System.Type的一个实例,它代表了目标类型实例。System.Type提供了获取类型信息的所有方法。主要是通过object.GetType()和typeof()操作符达到这个目的。
- 使用GetType()
Object 对象包含一个GetType()成员,成功调用GetType()的关键在于获得一个对象实例。例如:静态类无法实例化,无法调用GetType()。
DateTime dateTime = new DateTime();
Type type = dateTime.GetType();
// 获取该类型的所有公共属性
foreach (System.Reflection.PropertyInfo property in type.GetProperties())
{
Console.WriteLine(property.Name);
}
输出:
typeof()
在编译时绑定到特定的Type实例,并直接获取类型作为参数。int value = (int)Enum.Parse(typeof(ThreadPriorityLevel), "Idle"); Console.WriteLine(value);
也可以使用typeof表达式验证value对象的类型:
if (value.GetType() == typeof(int)) { // ... }
其中GetType() 在运行时返回对象的类型(晚期绑定),typeof()返回指定类的类型(早期绑定,编译时已知)
尽量采用typeof()这个操作符获取Type对象,因为操作符生成的代码通常更快。
成员调用
使用System.Type访问元数据后,可调用他们。
public class MagicClass
{
private int magicBaseValue;
public MagicClass()
{
magicBaseValue = 9;
}
public int ItsMagic(int preMagic)
{
return preMagic * magicBaseValue;
}
}
class Program
{
static void Main(string[] args)
{
// 获取构造函数,并创建一个MagicClass的实例
Type magicType = typeof(MagicClass);
ConstructorInfo magicConstructor = magicType.GetConstructor(Type.EmptyTypes);
object magicClassObject = magicConstructor.Invoke( new object[] { });
// 获取ItsMagic方法并使用100的参数值进行调用
MethodInfo magicMethod = magicType.GetMethod("ItsMagic");
// Invoke方法第一个值为:要在其上调用方法或构造函数的实例对象
// Invoke方法第一个值为:被调用方法或构造函数的参数列表。
object magicValue = magicMethod.Invoke(magicClassObject, new object[] { 100 });
Console.WriteLine("MethodInfo.Invoke()");
Console.WriteLine("MagicClass.ItsMagic() returned: {0}", magicValue);
}
结果:
泛型类型上的反射
- 在泛型类型上执行运行时反射,可以判断类型参数的类型:
public class Stack1<T>
{
public void Add(T i)
{
// 判断类型参数的类型
Type t = typeof(T);
}
}
在获得类型参数的Type对象实例化后,就可在类型参数上执行反射,从而判断他的行为,并针对具体类型来调整Add方法,使其能更有效地支持这种类型。
- 为泛型类或方法获取类型参数
public class Stack1<T>
{
public void Add(T i)
{
// 判断类型参数的类型
Type t = typeof(T);
}
}
class Program
{
static void Main(string[] args)
{
// 2、为泛型类或方法获取类型参数
Type t = typeof(Stack1<int>);
foreach (Type t1 in t.GetGenericArguments())
{
Console.WriteLine("Type parameter:" + t1.FullName);
}
}
结果:
特性
特性就是对象,所以定义特性要定义类。它们只是将一些附加信息与某个目标元素关联起来的方式。
创建自定义特性
//1 要继承System.Attribute
//2 要为自定义特性类添加Attribute后缀
public class AnimalTypeAttribute : Attribute
{
}
查找特性
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace CustomAttribute.Simple
{
public enum Animal
{
// Pets.
Dog = 1,
Cat,
Bird,
}
// 限制特性能修饰哪些构造
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class AnimalTypeAttribute : Attribute
{
// 提供特性构造函数初始化
public AnimalTypeAttribute(Animal pet)
{
thePet = pet;
}
protected Animal thePet;
public Animal Pet
{
get { return thePet; }
set { thePet = value; }
}
}
public class AnimalType1Attribute : Attribute
{
public Animal thePet;
}
public class AnimalTypeTestClass
{
[AnimalType(Animal.Dog)]
public void DogMethod() { }
[AnimalType(Animal.Cat)]
public void CatMethod() { }
[AnimalType(Animal.Bird)]
public void BirdMethod() { }
// 公共属性初始化
[AnimalType1(thePet = Animal.Bird)]
public void PigMethod() { }
}
class Program
{
static void Main(string[] args)
{
List<String> missing = new List<string>();
Type type1 = typeof(AnimalTypeTestClass);
MemberInfo[] memberInfos = type1.GetMethods();
foreach (MemberInfo memberInfo in memberInfos)
{
// 查找指定的特性
var attr = memberInfo.GetCustomAttribute(typeof(AnimalTypeAttribute)) as AnimalTypeAttribute;
if (attr != null)
{
Console.WriteLine(attr.Pet);
}
}
}
}
}
输出:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。