C# Harmony Transpiler 空字段异常,适用于两个几乎相同的调用之一

C# Harmony Transpiler null field exception for one of two nearly identical calls

提问人:jmucchiello 提问时间:9/1/2023 最后编辑:user16217248jmucchiello 更新时间:10/11/2023 访问量:103

问:

这是我的代码。问题在底部:

namespace DifficultyModNS
{
    [HarmonyPatch(typeof(Boosterpack),nameof(Boosterpack.Clicked))]
    public class OneVillagerChecks
    {
        public static Int32 frequency = 5;
        public static Int32 startChecking = 10;

        static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
        {
            foreach (var instruction in instructions)
            {
                if (instruction.opcode == OpCodes.Ldc_I4_5)
                {
                    DifficultyMod.Log("Transpiling const 5 to variable");
                    yield return new CodeInstruction(OpCodes.Ldfld, operand: AccessTools.Field(typeof(Int32), name: "DifficultyModNS.OneVillagerChecks::frequency"));
                }
                else if (instruction.opcode == OpCodes.Ldc_I4_S && Convert.ToInt32(instruction.operand) == 10)
                {
                    DifficultyMod.Log("Transpiling const 10 to variable");
                    yield return new CodeInstruction(OpCodes.Ldfld, operand: AccessTools.Field(typeof(Int32), name: "DifficultyModNS.OneVillagerChecks::startChecking"));
                }
                else
                {
                    yield return instruction;
                }
            }
        }
    }
}

打印第一条日志消息。然后,在第二条日志消息之后,有一个异常:

[17:18:44] [Log : difficulty_mod] Transpiling const 5 to variable
[17:18:44] [Log : difficulty_mod] Transpiling const 10 to variable
ArgumentNullException: Invalid argument for ldfld NULL
Parameter name: operand
  at HarmonyLib.Internal.Patching.ILManipulator.WriteTo (Mono.Cecil.Cil.MethodBody body, System.Reflection.MethodBase original) [0x001b4] in <4a2409e6eb214388b8d6ab81d407350d>:0 
  at HarmonyLib.Public.Patching.HarmonyManipulator.WriteTranspilers () [0x00084] in <4a2409e6eb214388b8d6ab81d407350d>:0 
  at HarmonyLib.Public.Patching.HarmonyManipulator.WriteImpl () [0x00031] in <4a2409e6eb214388b8d6ab81d407350d>:0 
Rethrow as HarmonyException: IL Compile Error (unknown location)
  at HarmonyLib.Public.Patching.HarmonyManipulator.WriteImpl () [0x00382] in <4a2409e6eb214388b8d6ab81d407350d>:0 
  at HarmonyLib.Public.Patching.HarmonyManipulator.Process (MonoMod.Cil.ILContext ilContext, System.Reflection.MethodBase originalMethod) [0x00042] in <4a2409e6eb214388b8d6ab81d407350d>:0 
  at HarmonyLib.Public.Patching.HarmonyManipulator.Manipulate (System.Reflection.MethodBase original, HarmonyLib.PatchInfo patchInfo, MonoMod.Cil.ILContext ctx) [0x00006] in <4a2409e6eb214388b8d6ab81d407350d>:0 
  at HarmonyLib.Public.Patching.HarmonyManipulator.Manipulate (System.Reflection.MethodBase original, MonoMod.Cil.ILContext ctx) [0x00007] in <4a2409e6eb214388b8d6ab81d407350d>:0 
  at HarmonyLib.Public.Patching.ManagedMethodPatcher.Manipulator (MonoMod.Cil.ILContext ctx) [0x00012] in <4a2409e6eb214388b8d6ab81d407350d>:0 
  at MonoMod.Cil.ILContext.Invoke (MonoMod.Cil.ILContext+Manipulator manip) [0x00087] in <92bbbc5a09fc417ca7426fbdd31824c2>:0 
  at MonoMod.RuntimeDetour.ILHook+Context.InvokeManipulator (Mono.Cecil.MethodDefinition def, MonoMod.Cil.ILContext+Manipulator cb) [0x00012] in <925d74c1e4e3467a888e7df55b8370c5>:0 
  at (wrapper dynamic-method) MonoMod.RuntimeDetour.ILHook+Context.DMD<MonoMod.RuntimeDetour.ILHook+Context::Refresh>(MonoMod.RuntimeDetour.ILHook/Context)
  at (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.Trampoline<MonoMod.RuntimeDetour.ILHook+Context::Refresh>?1194592624(object)
  at HarmonyLib.Internal.RuntimeFixes.StackTraceFixes.OnILChainRefresh (System.Object self) [0x00000] in <4a2409e6eb214388b8d6ab81d407350d>:0 
  at MonoMod.RuntimeDetour.ILHook.Apply () [0x00059] in <925d74c1e4e3467a888e7df55b8370c5>:0 
  at HarmonyLib.Public.Patching.ManagedMethodPatcher.DetourTo (System.Reflection.MethodBase replacement) [0x00047] in <4a2409e6eb214388b8d6ab81d407350d>:0 
// there's more but it's just additional subsystems rethrowing

为什么当两个字段在同一类中彼此相邻时,其中一个有效而另一个不起作用:

yield return new CodeInstruction(OpCodes.Ldfld, operand: AccessTools.Field(typeof(Int32), name: "DifficultyModNS.OneVillagerChecks::frequency"));
yield return new CodeInstruction(OpCodes.Ldfld, operand: AccessTools.Field(typeof(Int32), name: "DifficultyModNS.OneVillagerChecks::startChecking"));

编辑:我删除了“不起作用”的else if,并且我发现在此函数退出后仍然发生异常。所以现在我想问题是,当名称应该存在时,为什么操作数的 NULL 返回给 Ldfld?

编辑2:我使用了错误的IL指令。Harmony AccessTools 库是获取 FieldInfo 的垃圾。这被替换为 .typeof(OneVillagerChecks).GetField("frequency")

C# 转译器 和谐

评论

0赞 Ben Voigt 9/1/2023
1.在一行代码中少做一些事情。2. 向我们提供有关该方法的一些详细信息。是你写的吗?是某个图书馆吗?如果是库函数,请提供库的名称和完整名称,包括命名空间,以便我们知道您在说什么。AccessTools.Field
1赞 Ben Voigt 9/1/2023
看起来您正在为 的两个参数传递完全错误的值。文档需要声明类型,而不是属性类型。AccessTools.Field
0赞 jmucchiello 9/1/2023
我使用了错误的 IL 指令。AccessTools 是 Harmony 的一部分。

答: 暂无答案