维护提醒

BWIKI 全站将于 9 月 3 日(全天)进行维护,期间无法编辑任何页面或发布新的评论。

全站通知:

模组:制作指南/APIs/Reflection

来自星露谷物语维基
跳到导航 跳到搜索

模组:目录

反射接口(reflection API)允许您访问通常情况下不能访问的字段、属性或方法。您可以在您的入口方法中调用 helper.Reflection,或者在您的入口类中调用 this.Helper.Reflection 以使用反射接口。

介绍

反射(Reflection)是 C# 的一项强大功能,能使代码分析代码或与代码交互。SMAPI 提供了一个简化的反射接口,主要用于访问私有的游戏字段、属性和方法。SMAPI 会自动处理验证、缓存和性能优化。

基本反射

概览

SMAPI 提供了三个重载方法以访问代码:GetFieldGetPropertyGetMethod。每个方法都有如下三个参数:

参数 含义
objtype 您希望访问的、拥有私有字段/属性/方法的实例(若访问静态成员,则为相应类型)。
name 私有字段/属性/方法的名称。
required 若无法找到指定字段/属性/方法,是否抛出一个描述性异常。默认为 true。如果设为 false,最会返回 null,因此您需要手动验证。

每个方法都会返回一个对象,您可以对这个对象进行进一步的操作,例如获取和设置(getting/setting)字段/属性的值,或调用方法。

字段和属性

GetFieldGetProperty 的使用方法相同。它们返回的对象都有两个方法: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 的反射接口添加了缓存和优化;如果您希望自行实现反射,需要自己设计缓存和优化。