private static string GetMethodSignature(MethodInfo method, InterceptMethodAttribute attribute)
        {
            var returnType = method.ReturnType;
            var parameters = method.GetParameters().Select(p => p.ParameterType).ToArray();

            var requiredParameterTypes = new[] { typeof(int), typeof(int), typeof(long) };
            var lastParameterTypes     = parameters.Skip(parameters.Length - requiredParameterTypes.Length);

            if (attribute.MethodReplacementAction == MethodReplacementActionType.ReplaceTargetMethod)
            {
                if (!lastParameterTypes.SequenceEqual(requiredParameterTypes))
                {
                    throw new Exception(
                              $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet parameter requirements. " +
                              "Wrapper methods must have at least 3 parameters and the last 3 must be of types Int32 (opCode), Int32 (mdToken), and Int64 (moduleVersionPtr).");
                }
            }
            else if (attribute.MethodReplacementAction == MethodReplacementActionType.InsertFirst)
            {
                if (attribute.CallerAssembly == null || attribute.CallerType == null || attribute.CallerMethod == null)
                {
                    throw new Exception(
                              $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet InterceptMethodAttribute requirements. " +
                              "Currently, InsertFirst methods must have CallerAssembly, CallerType, and CallerMethod defined. " +
                              $"Current values: CallerAssembly=\"{attribute.CallerAssembly}\", CallerType=\"{attribute.CallerType}\", CallerMethod=\"{attribute.CallerMethod}\"");
                }
                else if (parameters.Any())
                {
                    throw new Exception(
                              $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet parameter requirements. " +
                              "Currently, InsertFirst methods must have zero parameters.");
                }
                else if (returnType != typeof(void))
                {
                    throw new Exception(
                              $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet return type requirements. " +
                              "Currently, InsertFirst methods must have a void return type.");
                }
            }

            var signatureHelper = SignatureHelper.GetMethodSigHelper(method.CallingConvention, returnType);

            signatureHelper.AddArguments(parameters, requiredCustomModifiers: null, optionalCustomModifiers: null);
            var signatureBytes = signatureHelper.GetSignature();

            if (method.IsGenericMethod)
            {
                // if method is generic, fix first byte (calling convention)
                // and insert a second byte with generic parameter count
                const byte IMAGE_CEE_CS_CALLCONV_GENERIC = 0x10;
                var        genericArguments = method.GetGenericArguments();

                var newSignatureBytes = new byte[signatureBytes.Length + 1];
                newSignatureBytes[0] = (byte)(signatureBytes[0] | IMAGE_CEE_CS_CALLCONV_GENERIC);
                newSignatureBytes[1] = (byte)genericArguments.Length;
                Array.Copy(signatureBytes, 1, newSignatureBytes, 2, signatureBytes.Length - 1);

                signatureBytes = newSignatureBytes;
            }

            return(string.Join(" ", signatureBytes.Select(b => b.ToString("X2"))));
        }
        public void AllMethodsHaveProperlyFormedTargetSignatureTypes(MethodInfo wrapperMethod, InterceptMethodAttribute attribute)
        {
            Assert.True(
                attribute.TargetSignatureTypes != null,
                $"{wrapperMethod.DeclaringType.Name}.{wrapperMethod.Name}: {nameof(attribute.TargetSignatureTypes)} definition missing.");

            // add 1 for return type, subtract 3 for extra parameters (opcode, mdToken, moduleVersionPtr)
            // 1 - 3 = -2
            var expectedParameterCount = wrapperMethod.GetParameters().Length - 2;

            if (!StaticInstrumentations.Contains(wrapperMethod))
            {
                // Subtract the instance (this) parameter
                expectedParameterCount--;
            }

            var typeSigLength = attribute.TargetSignatureTypes.Length;

            Assert.True(
                expectedParameterCount == typeSigLength,
                $"{wrapperMethod.DeclaringType.Name}.{wrapperMethod.Name}: {nameof(attribute.TargetSignatureTypes)} has {typeSigLength} items, expected {expectedParameterCount}.");

            Assert.False(
                attribute.TargetSignatureTypes.Any(string.IsNullOrWhiteSpace),
                $"{wrapperMethod.DeclaringType.Name}.{wrapperMethod.Name}: {nameof(attribute.TargetSignatureTypes)} has null or empty arguments.");
        }