Json 反序列化多态类型而不使用程序集名称,只使用Newtonsoft lib

Json 反序列化多态类型而不使用程序集名称,只使用Newtonsoft lib,json,json.net,deserialization,Json,Json.net,Deserialization,我从一个json格式的服务接收到一些数据。数据的一部分是类BASE(比如)的对象。从中派生出许多类: 现在服务器发送一个固定结构的json,其中有一个BASE类型的对象。下面我列出了一些示例回复: "{"Status":"Success","B":{"$type":"B1","id":"123"},"C":null}" "{"Status":"Success","A":{"$type":"A3","name":"Jon"},"B":{"$type":"B2","id":"A34J"}}"

我从一个json格式的服务接收到一些数据。数据的一部分是类BASE(比如)的对象。从中派生出许多类:

现在服务器发送一个固定结构的json,其中有一个BASE类型的对象。下面我列出了一些示例回复:

"{"Status":"Success","B":{"$type":"B1","id":"123"},"C":null}"

"{"Status":"Success","A":{"$type":"A3","name":"Jon"},"B":{"$type":"B2","id":"A34J"}}"
我在客户端模型中定义了相同的类层次结构,我使用NewtonSoft Json库来反序列化内容。正如您所看到的,服务器正在发送从基类派生的每个对象的$type信息,我希望能够在客户端反序列化期间将这些对象加载到它们各自的类型中。我将json反序列化为Response类型的对象

class Response
{
   string Status;
   BASE object1;
   BASE object2;
}

Response resp = JsonConvert.DeserializeObject<Response>( jsonServiceMsg, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Binder = mycustombinder });
类响应
{
字符串状态;
基本对象1;
基本对象2;
}
Response resp=JsonConvert.DeserializeObject(jsonServiceMsg,新的JsonSerializerSettings{TypeNameHandling=TypeNameHandling.Auto,Binder=mycustombinder});
如您所见,我没有在响应对象中指定对象B1、A3或B2的确切类型,我希望Newtonsoft库使用基于json消息中$type值的适当类型初始化object1和object2

请注意,服务有以下类(基本类和所有派生类) 在不同的命名空间中定义,在不同的 命名空间。但为了简单起见,服务不绑定名称空间 通过在序列化为json响应时使用自定义绑定

我知道我可以通过定义自定义绑定器(从SerializationBinder派生的类)并重写BindToName和BindToType属性()来实现这一点


但问题是我们不想使用System.Runtime.Serialization中的Json.Net SerializationBinder。我们的模块只能使用Newtonsoft库。对此有什么解决方案吗?

dbc建议编写一个自定义JsonConverter,如所用

我想会是这样的:

public override object ReadJson(JsonReader reader, 
        Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject item = JObject.Load(reader);
        switch (item[$type].Value<string>())
        {
            case "B1":
                return item.ToObject<B1>();
            case "B2":
                return item.ToObject<B2>();
            case "C1":
                return item.ToObject<C1>();
            case "A1":
                return item.ToObject<A1>();
            case "A2":
                return item.ToObject<A2>();
            case "A3":
                return item.ToObject<A3>();
        }
    }
public override object ReadJson(JsonReader,
类型objectType、对象existingValue、JsonSerializer序列化程序)
{
JObject item=JObject.Load(读卡器);
开关(项[$type].Value())
{
案例“B1”:
返回item.ToObject();
案例“B2”:
返回item.ToObject();
案例“C1”:
返回item.ToObject();
案例“A1”:
返回item.ToObject();
案例“A2”:
返回item.ToObject();
案例“A3”:
返回item.ToObject();
}
}
类似地,我必须编写定制JsonConverter的WriteJson方法。这就是你说的dbc吗

如果是,我有几个问题:

  • 这个代码的性能如何?每次调用JObject.Load(reader)似乎都很昂贵
  • 如果基类型对象嵌套在json的深处,它会正常工作吗

  • 您可以为
    Base
    创建一个自定义
    JsonConverter
    ,方法如下。即使在这种情况下,您确实有类型信息,您也会在转换器中按照答案的思路手动处理它。我收到的json非常大,两个基本类型对象只是其中的一部分。如果我使用自定义JsonConverter,您不认为我将不得不编写太多代码吗。我也必须序列化它。这不是太多的代码吗?
    JsonConverter
    将用于
    Base
    及其抽象子类。您所需要做的就是维护一个从类型名到类型的查找字典。JSON的总体大小与此无关,而其他类的数量与此无关。当然,编写自己的
    SerializationBinder
    会更容易,这是解决此问题的预期方法-但无论出于何种原因,您都不想这样做。请查看答案。这就是你的建议。1)你必须这样做。2) 是的,基本对象嵌套的深度无关紧要。如果你有一些问题,你可以用细节更新你的问题。这很有效。我列出了switch case中的所有子类型,并返回了它们的对象。但是WriteJson呢?我希望能够将此对象序列化回为多态类型保留$type属性的字符串。如何编写WriteJson,使其仅针对多态类型在Json中编写$type属性。{“Status”:“Success”,“A”:{“$type”:“A3”,“name”:“Jon”},“B”:{“$type”:“B2”,“id”:“A34J”}”