2

相关问题:JSON.NET - 将 JSON 反序列化为对象,该类类型在内部字段中(但这是特定于 JSON.NET)

是否有标准推荐的反序列化方法,例如:

{
  "command" : "register_user",
  "params" : {
    "@c" : "register_params",
    "name" : "sdfsd",
    "email" : "sdfsd@ddkdk",
    "password" : "JDFffJJJd",
    "address" : {
       "postcode" : "12345",
       "street" : "cherry st",
       "number" : "44432",
       "country" : "antarctica"
    }
  }
}

如果我们告诉反序列化器期望一个Message类型:

class Message
{
  string Command;
  object[] params;
}

似乎没有可以处理这种情况的 JSON 反序列化框架(或其中的文档)。

  1. 也许有一个或大多数框架可以简单地扫描程序集中加载的类型以找到最接近的类型?
  2. 也许在 JSON 标准中有一个标准字段类型可以帮助反序列化器选择正确的类型?
  3. 也许除了手动包含此类帮助程序(在 JSON 字符串和反序列化器逻辑中)之外别无选择?

谢谢

更新

对于此处的这个特定示例,隐含的用途是用于 RPC。在我的 RPC 解决方案中,需要将服务器对象绑定到 RPC 系统,并且每个 RPC 方法的 MethodInfo 都被缓存 - 因此每个参数的类型确实可以从 MethodInfo 输入到 JSON 反序列化器中。尽管如此,这个问题仍然是相关的,例如,如果图形变得更深,对象更复杂,那么即使这样也不够。此外,我确信这个问题已经/将会/在 RPC 案例之外遇到。所有的答案都可能是新奇的,我会简单地选择我认为最好的解决方案。

4

1 回答 1

1

您可以将自定义SerializationBinder与 JSON.NET 和$type属性一起使用。

举个例子:

public class TypeNameSerializationBinder : SerializationBinder
{
    public string TypeFormat { get; private set; }

    public TypeNameSerializationBinder(string typeFormat)
    {
        TypeFormat = typeFormat;
    }

    public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        assemblyName = null;
        typeName = serializedType.Name;
    }

    public override Type BindToType(string assemblyName, string typeName)
    {
        var resolvedTypeName = string.Format(TypeFormat, typeName);
        return Type.GetType(resolvedTypeName, true);
    }
}

现在让我们假设您有以下 JSON:

{
  "command" : "register_user",
  "params" : {
    "$type" : "Person",
    "name" : "sdfsd",
    "email" : "sdfsd@ddkdk",
    "password" : "JDFffJJJd",
    "address" : {
       "postcode" : "12345",
       "street" : "cherry st",
       "number" : "44432",
       "country" : "antarctica"
    }
  }
}

并且您在程序集中有以下模型BarBaz

namespace FooBar
{
    public class Person
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public Address Address { get; set; }
    }

    public class Address
    {
        public string Postcode { get; set; }
        public string Street { get; set; }
        public string Number { get; set; }
        public string Country { get; set; }
    }
}

还有一个Message类:

public class Message
{
    public string Command { get; set; }
    public object Params { get; set; }
}

你可以像这样反序列化它:

var settings = new JsonSerializerSettings
{
    Binder = new TypeNameSerializationBinder("FooBar.{0}, BarBaz"),
    TypeNameHandling = TypeNameHandling.All
};
string json = ...
var message = JsonConvert.DeserializeObject<Message>(json, settings);
Debug.Assert(message.Params is Person);
于 2013-01-28T07:05:26.003 回答