正文的签名和方法实现中的声明不匹配
我想在运行时实现一个接口,但是当我执行时
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方法
上述就是C#学习教程:正文的签名和方法实现中的声明不匹配分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
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); }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/954210.html