Newtonsoft 序列化后 C# InvokeMethod 失败
C# InvokeMethod fail after Newtonsoft serialize
我正在使用 Type.InvokeMember 方法调用在 C# 中动态调用一个方法。
我有 2 种方法,一种接受字符串参数,另一种接受 int 参数。
该代码在代码中初始化时工作正常,但在 Newtonsoft.Json 序列化后失败。
调试没有帮助,因为类型似乎是正确的。完整代码如下:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace DynamicMethodCall
{
class Program
{
static void Main(string[] args)
{
List<Command> commands = new List<Command>()
{
new Command() { ClassName="Module1", MethodName="Method1", Parameters= new object[] { "1" } },
new Command() { ClassName="Module1", MethodName="Method2", Parameters= new object[] { 1 } }
};
foreach (var command in commands)
{
string result = command.Invoke();
Console.WriteLine(result);
}
File.WriteAllText("commands.json", JsonConvert.SerializeObject(commands));
commands = JsonConvert.DeserializeObject<List<Command>>(File.ReadAllText("commands.json"));
foreach (var command in commands)
{
string result = command.Invoke();
Console.WriteLine(result);
}
Console.ReadLine();
}
}
public class Command
{
public string ClassName { get; set; }
public string MethodName { get; set; }
public object[] Parameters { get; set; }
public string Invoke()
{
try
{
Type type = Type.GetType("DynamicMethodCall." + ClassName);
object instance = Activator.CreateInstance(type);
string response = (string)type.InvokeMember(MethodName,
BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance,
null, instance, Parameters);
return response;
}
catch (Exception ex)
{
return ex.Message;
}
}
}
public class Module1
{
public string Method1(string x)
{
return $"You called Method1 in Module1 with arg {x}.";
}
public string Method2(int x)
{
return $"You called Method2 in Module1 with arg {x}.";
}
}
}
它returns
- 您在模块 1 中使用参数 1 调用了方法 1。
- 您在模块 1 中使用参数 1 调用了方法 2。
- 您在模块 1 中使用参数 1 调用了方法 1。
- 未找到方法'DynamicMethodCall.Module1.Method2'。
意思是在Newtonsoft序列化-反序列化之后,带有int参数的方法不起作用。
有人知道问题出在哪里吗?
您期望 JSON 数值将被反序列化为 int
- 因为这就是它的开头。实际上,它被反序列化为 long
。我相信这就是“Json.NET 对没有小数点的数字所做的”。 (我看不到更改它的选项,而且我不确定是否有一个选项有意义。)
你可以通过在反序列化前后添加这一行来观察:
Console.WriteLine(commands[1].Parameters[0].GetType());
您说:“调试无济于事,因为类型似乎是正确的。” - 但在这种情况下,它们 不 正确,因为您最终会尝试使用 long
值调用该方法。
从根本上说,您序列化的信息比原来少 - 因为您没有序列化类型信息。虽然 Json.NET 确实有一个 TypeNameHandling
设置在某些情况下可以帮助解决这个问题,但我还没有设法说服它简单地传播实际类型(以便它可以反序列化)。
或者,您可以 use a custom converter to deserialize to int
instead。但是,当然,如果您以 long
开头,那也是不正确的...
我正在使用 Type.InvokeMember 方法调用在 C# 中动态调用一个方法。
我有 2 种方法,一种接受字符串参数,另一种接受 int 参数。
该代码在代码中初始化时工作正常,但在 Newtonsoft.Json 序列化后失败。
调试没有帮助,因为类型似乎是正确的。完整代码如下:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace DynamicMethodCall
{
class Program
{
static void Main(string[] args)
{
List<Command> commands = new List<Command>()
{
new Command() { ClassName="Module1", MethodName="Method1", Parameters= new object[] { "1" } },
new Command() { ClassName="Module1", MethodName="Method2", Parameters= new object[] { 1 } }
};
foreach (var command in commands)
{
string result = command.Invoke();
Console.WriteLine(result);
}
File.WriteAllText("commands.json", JsonConvert.SerializeObject(commands));
commands = JsonConvert.DeserializeObject<List<Command>>(File.ReadAllText("commands.json"));
foreach (var command in commands)
{
string result = command.Invoke();
Console.WriteLine(result);
}
Console.ReadLine();
}
}
public class Command
{
public string ClassName { get; set; }
public string MethodName { get; set; }
public object[] Parameters { get; set; }
public string Invoke()
{
try
{
Type type = Type.GetType("DynamicMethodCall." + ClassName);
object instance = Activator.CreateInstance(type);
string response = (string)type.InvokeMember(MethodName,
BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance,
null, instance, Parameters);
return response;
}
catch (Exception ex)
{
return ex.Message;
}
}
}
public class Module1
{
public string Method1(string x)
{
return $"You called Method1 in Module1 with arg {x}.";
}
public string Method2(int x)
{
return $"You called Method2 in Module1 with arg {x}.";
}
}
}
它returns
- 您在模块 1 中使用参数 1 调用了方法 1。
- 您在模块 1 中使用参数 1 调用了方法 2。
- 您在模块 1 中使用参数 1 调用了方法 1。
- 未找到方法'DynamicMethodCall.Module1.Method2'。
意思是在Newtonsoft序列化-反序列化之后,带有int参数的方法不起作用。 有人知道问题出在哪里吗?
您期望 JSON 数值将被反序列化为 int
- 因为这就是它的开头。实际上,它被反序列化为 long
。我相信这就是“Json.NET 对没有小数点的数字所做的”。 (我看不到更改它的选项,而且我不确定是否有一个选项有意义。)
你可以通过在反序列化前后添加这一行来观察:
Console.WriteLine(commands[1].Parameters[0].GetType());
您说:“调试无济于事,因为类型似乎是正确的。” - 但在这种情况下,它们 不 正确,因为您最终会尝试使用 long
值调用该方法。
从根本上说,您序列化的信息比原来少 - 因为您没有序列化类型信息。虽然 Json.NET 确实有一个 TypeNameHandling
设置在某些情况下可以帮助解决这个问题,但我还没有设法说服它简单地传播实际类型(以便它可以反序列化)。
或者,您可以 use a custom converter to deserialize to int
instead。但是,当然,如果您以 long
开头,那也是不正确的...