概念
在计算机科学中,反射(Reflection)是指在运行时检查、访问和修改程序结构的能力。它允许程序在运行时获取类型信息、访问对象的属性和方法,并动态地创建对象实例、调用方法和操作属性。
在 Unity 中,反射是通过使用 System.Reflection 命名空间中的类和方法来实现的。下面是一些反射的常见用途和概念:
-
获取类型信息:反射可以用来获取类、结构体、枚举和接口等类型的信息,包括名称、命名空间、成员变量、方法、属性等。您可以使用 Type 类来获取类型的信息。
-
创建对象实例:反射可以根据类型信息动态地创建对象实例。您可以使用 Activator 类的 CreateInstance 方法来实现。
-
调用方法和访问属性:反射允许您在运行时动态调用对象的方法和访问其属性。使用 MethodInfo 类可以调用方法,而使用 PropertyInfo 类可以获取和设置属性值。
-
动态加载程序集:反射可以用于动态加载程序集,这在开发插件和扩展性应用程序时非常有用。您可以使用 Assembly 类来加载和管理程序集。
用途
获取类型信息
-
GetType()
: 该方法用于获取对象的类型。例如,如果有一个名为 obj 的对象,您可以使用 obj.GetType() 获取其类型。object obj = new MyClass(); Type type = obj.GetType();
-
typeof()
: 该运算符用于获取指定类型的 Type 对象。您可以直接使用类型名称或类型字面量作为参数。Type type = typeof(MyClass);
-
Assembly.GetTypes()
: 该方法用于获取程序集中的所有类型。您可以使用 Assembly 类的静态方法 GetExecutingAssembly() 获取当前正在执行的程序集。Assembly assembly = Assembly.GetExecutingAssembly(); Type[] types = assembly.GetTypes();
-
Type.Name
: 获取类型的名称(不包括命名空间)。Type type = typeof(MyClass); string typeName = type.Name;
-
Type.FullName
: 获取类型的完全限定名称(包括命名空间)。Type type = typeof(MyClass); string fullTypeName = type.FullName;
-
Type.Namespace
: 获取类型所属的命名空间。Type type = typeof(MyClass); string namespaceName = type.Namespace;
创建对象实例
Activator.CreateInstance(Type type)
: 该方法使用指定的类型创建一个对象实例,并返回一个对该对象的引用。Type type = typeof(MyClass); object instance = Activator.CreateInstance(type);
Activator.CreateInstance(Type type, params object[] args)
: 如果类型具有参数化的构造函数,您可以使用此方法创建对象实例,并传递构造函数所需的参数。Type type = typeof(MyClass); object instance = Activator.CreateInstance(type, arg1, arg2, ...);
Activator.CreateInstance<T>()
: 该泛型方法用于创建指定类型的对象实例,并返回一个对该对象的引用。MyClass instance = Activator.CreateInstance<MyClass>();
Activator.CreateInstance<T>(params object[] args)
: 如果类型具有参数化的构造函数,您可以使用此方法创建对象实例,并传递构造函数所需的参数。MyClass instance = Activator.CreateInstance<MyClass>(arg1, arg2, ...);
请注意,使用反射创建对象实例时,需要确保类型是可实例化的,并且具有公共的构造函数。否则,将引发异常。
调用方法和访问属性
- 调用方法:
- 获取方法信息:使用
Type.GetMethod()
方法获取方法的 MethodInfo 对象。 - 调用方法:使用
MethodInfo.Invoke()
方法调用方法,并传递对象实例(如果是实例方法)和方法参数。
Type type = typeof(MyClass); object instance = Activator.CreateInstance(type); MethodInfo methodInfo = type.GetMethod("MethodName"); methodInfo.Invoke(instance, null); // 调用无参数方法 // 调用带参数的方法 MethodInfo methodInfo = type.GetMethod("MethodName"); object[] parameters = new object[] { param1, param2 }; methodInfo.Invoke(instance, parameters);
- 获取方法信息:使用
- 访问属性:
- 获取属性信息:使用
Type.GetProperty()
方法获取属性的 PropertyInfo 对象。 - 获取属性值:使用
PropertyInfo.GetValue()
方法获取属性的值,并传递对象实例(如果是实例属性)。
Type type = typeof(MyClass); object instance = Activator.CreateInstance(type); PropertyInfo propertyInfo = type.GetProperty("PropertyName"); object value = propertyInfo.GetValue(instance); // 获取属性值 // 设置属性值 PropertyInfo propertyInfo = type.GetProperty("PropertyName"); propertyInfo.SetValue(instance, value);
- 获取属性信息:使用
请注意,反射调用方法和访问属性时,需要确保方法和属性是可访问的(例如,公共方法和公共属性)。否则,将引发异常。
动态加载程序集
- 使用
System.Reflection.Assembly
类来加载程序集:- 如果要加载当前正在执行的程序集,可以使用
Assembly.GetExecutingAssembly()
方法来获取当前程序集。 - 如果要加载其他程序集,可以使用
Assembly.Load()
或Assembly.LoadFrom()
方法,根据程序集的名称或路径加载指定的程序集。
// 加载当前正在执行的程序集 Assembly assembly = Assembly.GetExecutingAssembly(); // 加载指定的程序集 Assembly assembly = Assembly.Load("AssemblyName"); // 或者 Assembly assembly = Assembly.LoadFrom("Path/To/Assembly.dll");
- 如果要加载当前正在执行的程序集,可以使用
- 获取程序集中的类型和成员:
- 通过加载的程序集,可以使用
Assembly.GetTypes()
方法来获取程序集中的所有类型。 - 使用
Type.GetMembers()
、Type.GetMethods()
、Type.GetProperties()
等方法获取类型的成员信息。
Assembly assembly = Assembly.GetExecutingAssembly(); Type[] types = assembly.GetTypes(); foreach (Type type in types) { Console.WriteLine("Type: " + type.FullName); MemberInfo[] members = type.GetMembers(); foreach (MemberInfo member in members) { Console.WriteLine("Member: " + member.Name); } }
- 通过加载的程序集,可以使用
- 创建对象实例和调用方法:
- 根据类型信息,您可以使用反射创建对象实例和调用方法,就像之前介绍的创建对象实例和调用方法的方式一样。
Assembly assembly = Assembly.GetExecutingAssembly(); Type type = assembly.GetType("Namespace.ClassName"); object instance = Activator.CreateInstance(type); MethodInfo methodInfo = type.GetMethod("MethodName"); methodInfo.Invoke(instance, null);
需要注意的是,在动态加载程序集时,确保程序集存在并且可访问。