void ReversePatch(ref MethodBase lastOriginal)
 {
     for (var i = 0; i < patchMethods.Count; i++)
     {
         var patchMethod = patchMethods[i];
         if (patchMethod.type == HarmonyPatchType.ReversePatch)
         {
             lastOriginal = patchMethod.info.GetOriginalMethod();
             var reversePatcher = instance.CreateReversePatcher(lastOriginal, patchMethod.info);
             lock (PatchProcessor.locker)
                 _ = reversePatcher.Patch();
         }
     }
 }
        private void PrepareType()
        {
            var mainPrepareResult = RunMethod <HarmonyPrepare, bool>(true);

            if (mainPrepareResult == false)
            {
                return;
            }

            var originalMethodType = containerAttributes.methodType;

            // MethodType default is Normal
            if (containerAttributes.methodType == null)
            {
                containerAttributes.methodType = MethodType.Normal;
            }

            var reversePatchAttr    = typeof(HarmonyReversePatch).FullName;
            var reversePatchMethods = container.GetMethods(AccessTools.all).Where(m => m.GetCustomAttributes(true).Any(a => a.GetType().FullName == reversePatchAttr)).ToList();

            foreach (var reversePatchMethod in reversePatchMethods)
            {
                var attr           = containerAttributes.Merge(new HarmonyMethod(reversePatchMethod));
                var originalMethod = GetOriginalMethod(attr);
                var reversePatcher = instance.CreateReversePatcher(originalMethod, reversePatchMethod);
                reversePatcher.Patch();
            }

            var customOriginals = RunMethod <HarmonyTargetMethods, IEnumerable <MethodBase> >(null);

            if (customOriginals != null)
            {
                originals.Clear();
                originals.AddRange(customOriginals);
            }
            else
            {
                var isPatchAll = container.GetCustomAttributes(true).Any(a => a.GetType().FullName == typeof(HarmonyPatchAll).FullName);
                if (isPatchAll)
                {
                    var type = containerAttributes.declaringType;
                    originals.AddRange(AccessTools.GetDeclaredConstructors(type).Cast <MethodBase>());
                    originals.AddRange(AccessTools.GetDeclaredMethods(type).Cast <MethodBase>());
                    var props = AccessTools.GetDeclaredProperties(type);
                    originals.AddRange(props.Select(prop => prop.GetGetMethod(true)).Where(method => method != null)
                                       .Cast <MethodBase>());
                    originals.AddRange(props.Select(prop => prop.GetSetMethod(true)).Where(method => method != null)
                                       .Cast <MethodBase>());
                }
                else
                {
                    var original = RunMethod <HarmonyTargetMethod, MethodBase>(null) ?? GetOriginalMethod(containerAttributes);

                    if (original == null)
                    {
                        var info = "(";
                        info += $"declaringType={containerAttributes.declaringType}, ";
                        info += $"methodName ={containerAttributes.methodName}, ";
                        info += $"methodType={originalMethodType}, ";
                        info += $"argumentTypes={containerAttributes.argumentTypes.Description()}";
                        info += ")";
                        throw new ArgumentException(
                                  $"No target method specified for class {container.FullName} {info}");
                    }

                    originals.Add(original);
                }
            }

            GetPatches(container, out var prefixMethod, out var postfixMethod, out var transpilerMethod,
                       out var finalizerMethod);
            if (prefix != null)
            {
                prefix.method = prefixMethod;
            }
            if (postfix != null)
            {
                postfix.method = postfixMethod;
            }
            if (transpiler != null)
            {
                transpiler.method = transpilerMethod;
            }
            if (finalizer != null)
            {
                finalizer.method = finalizerMethod;
            }

            if (prefixMethod != null)
            {
                if (prefixMethod.IsStatic == false)
                {
                    throw new ArgumentException($"Patch method {prefixMethod.GetID()} must be static");
                }

                var prefixAttributes = HarmonyMethodExtensions.GetFromMethod(prefixMethod);
                containerAttributes.Merge(HarmonyMethod.Merge(prefixAttributes)).CopyTo(prefix);
            }

            if (postfixMethod != null)
            {
                if (postfixMethod.IsStatic == false)
                {
                    throw new ArgumentException($"Patch method {postfixMethod.GetID()} must be static");
                }

                var postfixAttributes = HarmonyMethodExtensions.GetFromMethod(postfixMethod);
                containerAttributes.Merge(HarmonyMethod.Merge(postfixAttributes)).CopyTo(postfix);
            }

            if (transpilerMethod != null)
            {
                if (transpilerMethod.IsStatic == false)
                {
                    throw new ArgumentException($"Patch method {transpilerMethod.GetID()} must be static");
                }

                var transpilerAttributes = HarmonyMethodExtensions.GetFromMethod(transpilerMethod);
                containerAttributes.Merge(HarmonyMethod.Merge(transpilerAttributes)).CopyTo(transpiler);
            }

            if (finalizerMethod != null)
            {
                if (finalizerMethod.IsStatic == false)
                {
                    throw new ArgumentException($"Patch method {finalizerMethod.GetID()} must be static");
                }

                var finalizerAttributes = HarmonyMethodExtensions.GetFromMethod(finalizerMethod);
                containerAttributes.Merge(HarmonyMethod.Merge(finalizerAttributes)).CopyTo(finalizer);
            }
        }