BWIKI 全站将于 9 月 3 日(全天)进行维护,期间无法编辑任何页面或发布新的评论。
模组:制作指南/APIs/Reflection
← 模组:目录
反射接口(reflection API)允许您访问通常情况下不能访问的字段、属性或方法。您可以在您的入口方法中调用 helper.Reflection,或者在您的入口类中调用 this.Helper.Reflection 以使用反射接口。
介绍
反射(Reflection)是 C# 的一项强大功能,能使代码分析代码或与代码交互。SMAPI 提供了一个简化的反射接口,主要用于访问私有的游戏字段、属性和方法。SMAPI 会自动处理验证、缓存和性能优化。
基本反射
概览
SMAPI 提供了三个重载方法以访问代码:GetField、GetProperty 和 GetMethod。每个方法都有如下三个参数:
参数 | 含义 |
---|---|
obj 或 type | 您希望访问的、拥有私有字段/属性/方法的实例(若访问静态成员,则为相应类型)。 |
name | 私有字段/属性/方法的名称。 |
required | 若无法找到指定字段/属性/方法,是否抛出一个描述性异常。默认为 true。如果设为 false,最会返回 null,因此您需要手动验证。 |
每个方法都会返回一个对象,您可以对这个对象进行进一步的操作,例如获取和设置(getting/setting)字段/属性的值,或调用方法。
字段和属性
GetField 和 GetProperty 的使用方法相同。它们返回的对象都有两个方法:GetValue 用于获取当前字段/属性的值,SetValue 用于重写当前字段/属性的值。
您可以直接获取值:
// get value of instance field
bool wasPet = this.Helper.Reflection.GetField<bool>(pet, "wasPetToday").GetValue();
您也可以先保存反射对象,稍后再对反射对象进行操作:
// set value of static field
IReflectedField<int> soundTimer = this.Helper.Reflection.GetField<int>(typeof(Junimo), "soundTimer");
soundTimer.SetValue(100);
如果您需要多次访问字段/属性,可以复用反射对象,这有助于提升性能。
方法
GetMethod 返回的对象具有一个重载方法 Invoke。后者有两种形式:
- Invoke() 调用指定方法,无返回值
- Invoke<T>() 对用指定方法并且返回一个值,其中 T 为预期的返回值类型。
例如,下述代码调用 TV.getFortuneForecast 私有方法,并将其返回值存入变量 forecast。
string forecast = this.Helper.Reflection
.GetMethod(new TV(), "getFortuneForecast")
.Invoke<string>();
如果方法需要参数,您可以通过 Invoke 来添加参数:
Vector2 spawnTile = new Vector2(25, 25);
this.helper.Reflection
.GetMethod(Game1.getFarm(), "doSpawnCrow")
.Invoke(spawnTile);
高级反射
如果您需要实现更多功能,则可以访问反射接口底层的 C# 反射类型:
FieldInfo field = this.Helper.Reflection.GetField<string>(…).FieldInfo;
MethodInfo method = this.Helper.Reflection.GetMethod(…).MethodInfo;
甚至,您可以直接使用C# 反射。请注意,SMAPI 的反射接口添加了缓存和优化;如果您希望自行实现反射,需要自己设计缓存和优化。