static void AddField(ModuleDefinition module, NewFieldData newField) { var fieldType = GenTypes.GetTypeInAnyAssembly(newField.fieldType); var ceFieldType = module.ImportReference(fieldType); PrepatcherMod.Info($"Patching in a new field {newField.name} of type {ceFieldType.ToStringSafe()}/{newField.fieldType} in type {newField.targetType}"); var ceField = new FieldDefinition( newField.name, FieldAttributes.Public, ceFieldType ); if (newField.isStatic) { ceField.Attributes |= FieldAttributes.Static; } var targetType = module.GetType(newField.targetType); targetType.Fields.Add(ceField); if (newField.defaultValue != null) { WriteFieldInitializers(newField, ceField, fieldType); } }
static void WriteFieldInitializers(NewFieldData newField, FieldDefinition ceNewField, Type fieldType) { var targetType = ceNewField.DeclaringType; var i = targetType.Fields.IndexOf(ceNewField); foreach (var ctor in targetType.GetConstructors().Where(c => c.IsStatic == newField.isStatic)) { if (Util.CallsAThisCtor(ctor)) { continue; } var insts = (IList <Instruction>)ctor.Body.Instructions; int insertAt = -1; int lastValid = -1; for (int k = 0; k < insts.Count; k++) { var inst = insts[k]; insertAt = lastValid; if (inst.OpCode == OpCodes.Call && inst.Operand is MethodDefinition m && m.IsConstructor) { break; } if (inst.OpCode == OpCodes.Stfld && inst.Operand is FieldDefinition f) { if (targetType.Fields.IndexOf(f) > i) { break; } lastValid = k; } } insertAt++; var ilProc = ctor.Body.GetILProcessor(); var insertBefore = insts[insertAt]; if (!newField.isStatic) { ilProc.InsertBefore(insertBefore, Instruction.Create(OpCodes.Ldarg_0)); } if (newField.defaultValue == NewFieldData.DEFAULT_VALUE_NEW_CTOR) { ilProc.InsertBefore(insertBefore, Instruction.Create(OpCodes.Newobj, targetType.Module.ImportReference(fieldType.GetConstructor(new Type[0])))); } else { var defaultValueInst = Instruction.Create(OpCodes.Ret); var op = Util.GetConstantOpCode(newField.defaultValue).Value; defaultValueInst.OpCode = op; defaultValueInst.Operand = op == OpCodes.Ldc_I4 ? Convert.ToInt32(newField.defaultValue) : newField.defaultValue; ilProc.InsertBefore(insertBefore, defaultValueInst); } ilProc.InsertBefore(insertBefore, Instruction.Create(newField.isStatic ? OpCodes.Stsfld : OpCodes.Stfld, ceNewField)); } }