方法实现中的主体签名和声明不匹配 [英] Signature of the body and declaration in a method implementation do not match
本文介绍了方法实现中的主体签名和声明不匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我想在运行时实现一个接口,但是当我执行时
I want to implement an interface at runtime, however when i execute
return Activator.CreateInstance(typeBuilder.CreateTypeInfo().AsType(), new RPCRequestProxy());
在 RPCClientFactory.cs 中抛出
in RPCClientFactory.cs it throws
System.TypeLoadException: 主体和声明中的签名方法实现不匹配
.
我使用 dotnet 核心 1.0.4.
I use dotnet core 1.0.4.
入口点Program.cs:
The entry point 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<IRCPClient>();
var cli = factory.GetClient<IRCPClient>();
cli.Foo(1, "HelloWorld", DateTime.Now);
Console.ReadKey();
}
}
}
RPCClientFactory.cs:
public class RPCClientFactory
{
private readonly ConcurrentDictionary<Type, object> _clients = new ConcurrentDictionary<Type, object>();
public void Register<ClientType>()
{
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<string, object>).GetConstructor(new Type[0]));
il.Emit(OpCodes.Stloc_0);
for (var i = 0; i < paramters.Length; ++i)
{
var param = paramters[i];
if (param.GetCustomAttribute<BodyParamAttribute>() != 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<string, object>).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<ClientType>() where ClientType : class
{
_clients.TryGetValue(typeof(ClientType), out object cli);
return cli as ClientType;
}
public ClientType GetRequiredClient<ClientType>() where ClientType : class
{
var cli = GetClient<ClientType>();
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<string, object> urlParams)
{
await Task.Run(() =>
{
Console.WriteLine("URL:" + url);
Console.WriteLine("QueryString:");
foreach (var kv in urlParams)
{
Console.WriteLine($"{kv.Key}={kv.Value}");
}
});
}
}
注册IRCPClient后,我希望它生成一个这样的类:
After register IRCPClient, i hope it generates a class like this:
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<string, object>();
urlParams.Add(nameof(b), b);
urlParams.Add(nameof(a), a);
urlParams.Add(nameof(c), c);
return _proxy.PostAsync("xxx.xxx.xxx", urlParams);
}
}
推荐答案
最后,我解决了:
1:在使用本地值之前,我们必须DeclareLocal.
1: We must DeclareLocal before we use a local value.
2:将 paramters.Select(x => x.GetType()).ToArray()
更改为 paramters.Select(x => x.ParameterType).ToArray()
这是我在 RPCClientFactory.cs
This is my final CreateMethod method of RPCClientFactory.cs
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<string, object>)); // add this line
il.Emit(OpCodes.Newobj, typeof(Dictionary<string, object>).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<string, object>).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);
}
这篇关于方法实现中的主体签名和声明不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文