Closed
Description
openedon Nov 7, 2023
When using System.Reflection.Emit with Mono, using MethodBuilder.SetReturnType
and MethodBuilder.SetParameters
on methods that are supposed to implement interface methods does not work - the method is not considered to implement the interface method. Using the long form of TypeBuilder.DefineMethod
works.
using System;
using System.Reflection;
using System.Reflection.Emit;
public interface IStr
{
public string MStr(string x);
}
public class P {
public static void Main()
{
var aname = "TestAssembly";
var assemblyName = new AssemblyName(aname);
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(aname);
var typeBuilder = moduleBuilder.DefineType("TestType", TypeAttributes.Public, typeof(object), new Type[] { typeof(IStr) });
#if false
//works
var methodBuilder = typeBuilder.DefineMethod("MStr", MethodAttributes.Public | MethodAttributes.Virtual, typeof(string), new Type[] { typeof(string) });
#else
// throws "Invalid VTable" from CreateInstance, below
var methodBuilder = typeBuilder.DefineMethod("MStr", MethodAttributes.Public | MethodAttributes.Virtual);
methodBuilder.SetReturnType(typeof(string));
methodBuilder.SetParameters(new Type[] { typeof(string) });
#endif
var ilg = methodBuilder.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_1);
ilg.Emit(OpCodes.Ret);
var type = typeBuilder.CreateType();
var obj = Activator.CreateInstance(type);
var m = type.GetMethod("MStr");
var r = m.Invoke(obj, new object[] { "hello" });
Console.WriteLine($"r = {r}");
}
}
Update simpler repro and better diagnosis; original issue below
Needs some investigation still. Some of the System.Reflection.Emit code generates a class with a bad vtable on net8.0.
The TypedClientBuilder is from aspnetcore:
Repro:
Clone this repo https://github.com/lambdageek/repro-iclientproxy-vtable-fail
Expected
$ dotnet run
SendCoreAsync - M1
Actual
$ dotnet run
Unhandled Exception:
System.TypeLoadException: VTable setup of type Microsoft.AspNetCore.SignalR.TypedClientBuilder.I1Impl failed
at System.RuntimeType.GetMethodsByName(String name, BindingFlags bindingAttr, MemberListType listType, RuntimeType reflectedType)
at System.RuntimeType.GetMethodCandidates(String name, BindingFlags bindingAttr, CallingConventions callConv, Type[] types, Int32 genericParamCount, Boolean allowPrefixLookup)
at System.RuntimeType.GetMethodImpl(String name, Int32 genericParamCount, BindingFlags bindingAttr, Binder binder, CallingConventions callConv, Type[] types, ParameterModifier[] modifiers)
at System.RuntimeType.GetMethodImpl(String name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
at System.Type.GetMethod(String name, BindingFlags bindingAttr)
at Retrofit.TypedClientBuilder`1[[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].GenerateClientBuilder() in /private/tmp/promo/TypedClientBuilder.cs:line 42
at System.Lazy`1[[System.Func`2[[Retrofit.IClientProxy, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1[[System.Func`2[[Retrofit.IClientProxy, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1[[System.Func`2[[Retrofit.IClientProxy, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].CreateValue()
at System.Lazy`1[[System.Func`2[[Retrofit.IClientProxy, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].get_Value()
at Retrofit.TypedClientBuilder`1[[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].Build(IClientProxy proxy) in /private/tmp/promo/TypedClientBuilder.cs:line 24
at P.Main() in /private/tmp/promo/Program.cs:line 19
at P.<Main>()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment