正文的签名和方法实现中的声明不匹配

我想在运行时实现一个接口,但是当我执行时

return Activator.CreateInstance(typeBuilder.CreateTypeInfo().AsType(), new RPCRequestProxy()); 

在它抛出的RPCClientFactory.cs中

System.TypeLoadException: Signature of the body and declaration in a method implementation do not match

我使用dotnet core 1.0.4。

入口点Program.cs

 namespace RPC { interface IRCPClient { Task Foo([UrlParam]int b, [UrlParam]string a, [UrlParam] DateTime c); } class Program { static void Main(string[] args) { var factory = new RPCClientFactory(); factory.Register(); var cli = factory.GetClient(); cli.Foo(1, "HelloWorld", DateTime.Now); Console.ReadKey(); } } } 

RPCClientFactory.cs

  public class RPCClientFactory { private readonly ConcurrentDictionary _clients = new ConcurrentDictionary(); public void Register() { Register(typeof(ClientType)); } public void Register(Type type) { if (!_clients.TryAdd(type, CreateImplInstance(type))) throw new InvalidOperationException($"bad type{type}"); } public object CreateImplInstance(Type type) { var typeBuilder = CreateTypeBuilder(type); var methods = type.GetMethods(); var field = CreateFiled(typeBuilder); CreateCotr(typeBuilder, field); CreateMethods(typeBuilder, methods, field); typeBuilder.AddInterfaceImplementation(type); return Activator.CreateInstance(typeBuilder.CreateTypeInfo().AsType(), new RPCRequestProxy()); } private static TypeBuilder CreateTypeBuilder(Type type) { var typeSignature = "MyDynamicType"; var an = new AssemblyName(typeSignature); var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); TypeBuilder tb = moduleBuilder.DefineType(typeSignature, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout, null); return tb; } private static FieldInfo CreateFiled(TypeBuilder typeBuilder) { return typeBuilder.DefineField("_proxy", typeof(RPCRequestProxy), FieldAttributes.Private); } private static void CreateCotr(TypeBuilder typeBuilder, FieldInfo proxyField) { var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public , CallingConventions.Standard , new[] { typeof(RPCRequestProxy) }); var il = ctorBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[0])); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Stfld, proxyField); il.Emit(OpCodes.Ret); } public void CreateMethods(TypeBuilder typeBuilder, MethodInfo[] methods, FieldInfo field) { foreach (var method in methods) { CreateMethod(typeBuilder, method, field); } } private static void CreateMethod(TypeBuilder typeBuilder, MethodInfo method, FieldInfo proxyFiled) { var paramters = method.GetParameters(); var methodBuilder = typeBuilder.DefineMethod(method.Name, MethodAttributes.Public, CallingConventions.Standard, method.ReturnType, paramters.Select(x => x.GetType()).ToArray()); var il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Newobj, typeof(Dictionary).GetConstructor(new Type[0])); il.Emit(OpCodes.Stloc_0); for (var i = 0; i < paramters.Length; ++i) { var param = paramters[i]; if (param.GetCustomAttribute() != null) continue; il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldstr, param.Name); il.Emit(OpCodes.Ldarg, i + 1); if (param.ParameterType.GetTypeInfo().IsValueType) { il.Emit(OpCodes.Box, param.GetType()); } il.Emit(OpCodes.Callvirt, typeof(Dictionary).GetMethod("Add")); } var proxyMethod = typeof(RPCRequestProxy) .GetMethods() .First(x => x.Name == "PostAsync" && x.GetParameters().Length == 2); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, proxyFiled); il.Emit(OpCodes.Ldstr, "xxx.xxx.xxx"); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Callvirt, proxyMethod); il.Emit(OpCodes.Stloc_1); il.Emit(OpCodes.Ldloc_1); il.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(methodBuilder, method); } public ClientType GetClient() where ClientType : class { _clients.TryGetValue(typeof(ClientType), out object cli); return cli as ClientType; } public ClientType GetRequiredClient() where ClientType : class { var cli = GetClient(); if (cli == null) throw new InvalidOperationException($"bad type{typeof(ClientType)}"); return cli; } } 

RPCRequestProxy.cs

  public class RPCRequestProxy { public RPCRequestProxy() { } public async Task PostAsync(string url, IDictionary urlParams) { await Task.Run(() => { Console.WriteLine("URL:" + url); Console.WriteLine("QueryString:"); foreach (var kv in urlParams) { Console.WriteLine($"{kv.Key}={kv.Value}"); } }); } } 

注册IRCPClient后,我希望它生成一个这样的类:

  class RCPClient : IRCPClient { private readonly RPCRequestProxy _proxy; public RCPClient(RPCRequestProxy proxy) { _proxy = proxy; } public Task Foo([UrlParam] int b, [UrlParam] string a, [UrlParam] DateTime c) { var urlParams = new Dictionary(); urlParams.Add(nameof(b), b); urlParams.Add(nameof(a), a); urlParams.Add(nameof(c), c); return _proxy.PostAsync("xxx.xxx.xxx", urlParams); } } 

最后,我解决了这个问题:

1:在使用本地值之前,我们必须使用DeclareLocal

2:更改paramters.Select(x => x.GetType()).ToArray()paramters.Select(x => x.ParameterType).ToArray()

这是我RPCClientFactory.cs的最终CreateMethod方法

  private static void CreateMethod(TypeBuilder typeBuilder, MethodInfo method, FieldInfo proxyFiled) { var paramters = method.GetParameters(); var methodBuilder = typeBuilder.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.SpecialName, CallingConventions.Standard, method.ReturnType, paramters.Select(x => x.ParameterType).ToArray()); // change this line var il = methodBuilder.GetILGenerator(); il.DeclareLocal(typeof(Dictionary)); // add this line il.Emit(OpCodes.Newobj, typeof(Dictionary).GetConstructor(new Type[0])); il.Emit(OpCodes.Stloc_0); for (short i = 0; i < paramters.Length; ++i) { var param = paramters[i]; il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldstr, param.Name); il.Emit(OpCodes.Ldarg, (short)(i +1)); if (param.ParameterType.GetTypeInfo().IsValueType) { il.Emit(OpCodes.Box, param.ParameterType); } il.Emit(OpCodes.Callvirt, typeof(Dictionary).GetMethod("Add")); } var proxyMethod = typeof(RPCRequestProxy) .GetMethods() .First(x => x.Name == "PostAsync" && x.GetParameters().Length == 2); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, proxyFiled); il.Emit(OpCodes.Ldstr, "xxx.xxx.xxx"); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Callvirt, proxyMethod); il.Emit(OpCodes.Ret); }