当序列化时,我将ClassName写入对象的_CurrentClassName属性。当使用JSON.Net库读取json时,我需要将对象更改为此属性的值。
{
"Field1": 0,
"Field2": "34",
"_CurrentClassName": "MyCustomClass"
}
class CustomJsonConverter : JsonConverter
{
...
public override bool CanConvert(Type objectType)
{
return objectType.IsClass;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var value = existingValue;
if (reader.TokenType == JsonToken.Null)
{
return null;
}
else if (reader.TokenType == JsonToken.StartObject)
{
JObject jObject = JObject.Load(reader);
JToken jToken;
if (jObject.TryGetValue("_CurrentClassName", out jToken))
{
var t = jToken.Value<string>();
Type tt = Type.GetType(objectType.Namespace + "." + t);
value = Activator.CreateInstance(tt);
return value;
}
}
return serializer.Deserialize(reader);
}
...
}
答案 0 :(得分:0)
一旦推断出对象类型并且实例化了对象,就可以使用JsonSerializer.Populate(jObject.CreateReader())
来填充它。
例如:
from socketserver import ThreadingMixIn
from http.server import BaseHTTPRequestHandler, HTTPServer
import time
from gpiozero import DigitalOutputDevice
import logging
from time import sleep
logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s', level=logging.INFO)
hostName = ''
hostPort = 9001
busy = False
class ThreadingServer(ThreadingMixIn, HTTPServer):
pass
class MyServer(BaseHTTPRequestHandler):
def do_GET(self):
global busy
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(bytes("Hello!<br>", "utf-8"))
if self.path == '/gates':
if not busy:
busy = True
relay = DigitalOutputDevice(17) # Initialize GPIO 17
relay.on()
logging.info('Cycle started')
self.wfile.write(bytes("Cycle started<br>", "utf-8"))
sleep(2)
relay.close()
sleep(20)
relay = DigitalOutputDevice(17)
relay.on()
sleep(2)
relay.close()
logging.info('Cycle finished')
self.wfile.write(bytes("Cycle finished", "utf-8"))
busy = False
else:
# self.wfile.write(bytes("Busy now!<br>", "utf-8"))
self.send_error(503)
myServer = ThreadingServer((hostName, hostPort), MyServer)
print(time.asctime(), "Server Starts - %s:%s" % (hostName, hostPort))
try:
myServer.serve_forever()
except KeyboardInterrupt:
pass
myServer.server_close()
print(time.asctime(), "Server Stops - %s:%s" % (hostName, hostPort))
CustomCreationConverter<T>
也使用public abstract class CustomJsonConverterBase : JsonConverter
{
protected abstract Type InferType(JToken token, Type objectType, object existingValue);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var token = JToken.Load(reader);
var actualType = InferType(token, objectType, existingValue);
if (existingValue == null || existingValue.GetType() != actualType)
{
var contract = serializer.ContractResolver.ResolveContract(actualType);
existingValue = contract.DefaultCreator();
}
using (var subReader = token.CreateReader())
{
// Using "populate" avoids infinite recursion.
serializer.Populate(subReader, existingValue);
}
return existingValue;
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public class CustomJsonConverter : CustomJsonConverterBase
{
public const string ClassPropertyName = @"_CurrentClassName";
protected override Type InferType(JToken token, Type objectType, object existingValue)
{
if (token is JObject)
{
var typeName = (string)token[ClassPropertyName];
if (typeName != null)
{
var actualType = Type.GetType(objectType.Namespace + "." + typeName);
if (actualType != null)
return actualType;
}
}
return objectType;
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}
来填充刚刚分配的对象,因此这是解决此问题的标准方法。
请注意,您正在部分复制Json.NET的内置TypeNameHandling
功能。
答案 1 :(得分:0)
如果您未与_CurrentClassName
属性名称或其值语法结合,则可以使用Json.Net内置的类型处理。
序列化或反序列化时,您可以传入控制序列化或反序列化的JsonSerializerSettings
对象。
在此对象上,您可以设置一个TypeNameHandling
属性,该属性控制Json.Net如何序列化和反序列化正在处理的确切类型。
以下是LINQPad示例:
void Main()
{
var t = new Test { Key = 42, Value = "Meaning of life" };
var json = JsonConvert.SerializeObject(
t, Newtonsoft.Json.Formatting.Indented,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
Console.WriteLine(json);
var obj =JsonConvert.DeserializeObject(json,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
Console.WriteLine(obj.GetType().FullName);
}
public class Test
{
public int Key { get; set; }
public string Value { get; set; }
}
输出:
{
"$type": "UserQuery+Test, LINQPadQuery",
"Key": 42,
"Value": "Meaning of life"
}
UserQuery+Test
在这里,您可以看到反序列化返回的对象类型是Test
类。