Repository: dotnet/runtime
File: src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderTests.cs (C#)

Code before:
                    Assert.Equal("M", testMethod.ReturnType.Name);
                }
            }
        }

        [Fact]
        public void SaveInterfaceOverrideWithCustomModifier()
        {
            using (TempDirectory dir = new())
            {
                AssemblyName name = new("TestAssembly");
                PersistedAssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilder(name);
                ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module");
                TypeBuilder tb = mb.DefineType("IMethodWithModifiersImpl", TypeAttributes.Class | TypeAttributes.Public);
                tb.AddInterfaceImplementation(typeof(IMethodWithModifiers));
                MethodInfo mRun = typeof(IMethodWithModifiers).GetMethod(nameof(IMethodWithModifiers.Run))!;
                MethodBuilder m = tb.DefineMethod("IMethodWithModifiers.Run",
                    MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
                    CallingConventions.Standard,
                    returnType: typeof(void),
                    returnTypeRequiredCustomModifiers: [],
                    returnTypeOptionalCustomModifiers: [],
                    // typeof(delegate*<in long, void>) does not copy the modreq, so get the modified type from the interface method.
                    parameterTypes: [typeof(int).MakeByRefType(), mRun.GetParameters()[1].GetModifiedParameterType()],
                    parameterTypeRequiredCustomModifiers: [[typeof(InAttribute)], []],
                    parameterTypeOptionalCustomModifiers: [[], []]);
                // The method's parameter has a modreq; make sure it is added to the override's signature.
                // See https://github.com/dotnet/runtime/issues/123857
                tb.DefineMethodOverride(m, mRun);
                ParameterBuilder pb = m.DefineParameter(1, ParameterAttributes.In, "x");
                pb.SetCustomAttribute(new CustomAttributeBuilder(typeof(IsReadOnlyAttribute).GetConstructor(types: [])!, []));
                m.GetILGenerator().Emit(OpCodes.Ret);
                tb.CreateType();
                string assemblyPath = Path.Combine(dir.Path, $"{name.Name}.dll");
                assemblyBuilder.Save(assemblyPath);

                AssemblyLoadContext alc = new(nameof(SaveInterfaceOverrideWithCustomModifier), isCollectible: true);
                try
                {
                    // Load the assembly and check that loading the type does not throw.
                    Assembly loadedAsm = alc.LoadFromAssemblyPath(assemblyPath);
                    _ = loadedAsm.GetType(tb.Name, throwOnError: true);
                }
                finally
                {
                    alc.Unload();
                }
            }
        }

        [Fact]

Review comment (suggestion):
```suggestion
                    returnType: mRun.ReturnParameter.GetModifiedType(),
                    returnTypeRequiredCustomModifiers: null,
                    returnTypeOptionalCustomModifiers: null,
                    parameterTypes: mRun.GetParameters().Select(static p => p.GetModifiedParameterType()).ToArray(),
                    parameterTypeRequiredCustomModifiers: null,
                    parameterTypeOptionalCustomModifiers: null);
```
Would this work?

I am looking for a general-purpose code one would write to pass a MethodInfo signature into this method.

Code after:
                }
            }
        }

        [Fact]
        public void SaveInterfaceOverrideWithCustomModifier()
        {
            using (TempFile file = TempFile.Create())
            {
                AssemblyName name = new("TestAssembly");
                PersistedAssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilder(name);
                ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module");

                TypeBuilder tb = mb.DefineType("IMethodWithModifiersImpl", TypeAttributes.Class | TypeAttributes.Public);
                tb.AddInterfaceImplementation(typeof(IMethodWithModifiers));
                MethodInfo mRun = typeof(IMethodWithModifiers).GetMethod(nameof(IMethodWithModifiers.Run));
                MethodBuilder m = tb.DefineMethod("IMethodWithModifiers.Run",
                    MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
                    CallingConventions.Standard,
                    returnType: mRun.ReturnParameter.GetModifiedParameterType(),
                    returnTypeRequiredCustomModifiers: null,
                    returnTypeOptionalCustomModifiers: null,
                    // The first parameter will have modreqs specified from parameterTypeRequiredCustomModifiers, and the second from parameterTypes.
                    parameterTypes: mRun.GetParameters().Select((x, i) => i == 0 ? x.ParameterType : x.GetModifiedParameterType()).ToArray(),
                    parameterTypeRequiredCustomModifiers: [[typeof(InAttribute)], null],
                    parameterTypeOptionalCustomModifiers: null);
                tb.DefineMethodOverride(m, mRun);
                ParameterBuilder pb = m.DefineParameter(1, ParameterAttributes.In, "x");
                pb.SetCustomAttribute(new CustomAttributeBuilder(typeof(IsReadOnlyAttribute).GetConstructor(types: []), []));
                m.GetILGenerator().Emit(OpCodes.Ret);
                MethodInfo mRun2 = typeof(IMethodWithModifiers).GetMethod(nameof(IMethodWithModifiers.Run2));
                MethodBuilder m2 = tb.DefineMethod("IMethodWithModifiers.Run2",
                    MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
                    CallingConventions.Standard,
                    returnType: mRun2.ReturnParameter.GetModifiedParameterType(),
                    returnTypeRequiredCustomModifiers: null,
                    returnTypeOptionalCustomModifiers: null,
                    parameterTypes: mRun2.GetParameters().Select(x => x.GetModifiedParameterType()).ToArray(),
                    // Test that passing null gets modreqs from the parameter types.
                    parameterTypeRequiredCustomModifiers: null,
                    parameterTypeOptionalCustomModifiers: null);
                tb.DefineMethodOverride(m2, mRun2);
                ParameterBuilder pb2 = m2.DefineParameter(1, ParameterAttributes.In, "x");
                pb2.SetCustomAttribute(new CustomAttributeBuilder(typeof(IsReadOnlyAttribute).GetConstructor(types: []), []));
                m2.GetILGenerator().Emit(OpCodes.Ret);

                tb.CreateType();
                assemblyBuilder.Save(file.Path);

                TestAssemblyLoadContext context = new();
                // Load the assembly and check that loading the type does not throw.