反序列化JSON以使用.NET键入具有对象(非特定类型)内部字段的内容

时间:2013-01-28 06:32:16

标签: .net json oop

相关问题:JSON.NET - deserialize JSON into object, which class type is in inner field(但这个特定于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字符串和反序列化程序逻辑中)?
  4. 由于

    更新

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

1 个答案:

答案 0 :(得分:1)

您可以使用带有JSON.NET和SerializationBinder属性的自定义$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);