我反映了JSON.NET JavaScriptDateTimeConverter类代码,复制了它,并将该类重命名为3DateTimeConverter,以便修改它以更精确和强类型的庄园格式化DateTime对象。
我让它根据JSON.NET输出强类型对象的方式输出一个类型,如:{“$type”:“system.datetime,mscorlib”,“ticks”:0}
运行JsonConverter的重写WriteJson方法来生成该值。
但是,当我尝试使用与相同转换器完全相同的设置反序列化字符串时,重写的ReadJson方法永远没有机会运行并从ticks属性构造DateTime,因为会出现以下错误:
无法将当前JSON对象(例如{“name”:“value”})反序列化为类型“System.DateTime”,因为该类型需要一个JSON基元值(例如string、number、boolean或null)才能正确反序列化.
要修复此错误,可以将JSON更改为JSON基元值(例如,string、number、boolean、null),或者更改反序列化类型,使其成为可以从JSON对象反序列化的普通.NET类型(例如,不是像integer这样的基元类型,不是像数组或列表这样的集合类型)。还可以将JsonObjectAttribute添加到类型中,以强制它从JSON对象反序列化。
路径“滴答”,第1行,位置45。
这是否是某种bug或限制,它将不允许我恢复一个DateTime类型,因为它是一个value-type?还是我错过了什么?
下面是序列化设置:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
settings.PreserveReferencesHandling = PreserveReferencesHandling.All;
settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
settings.ConstructorHandling = ConstructorHandling.Default;
settings.TypeNameHandling = TypeNameHandling.All;
settings.TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
settings.DateParseHandling = DateParseHandling.DateTime;
settings.Converters.Add( new AS3DateTimeConverter() );
//settings.Binder = new AS3SerializationBinder();
string s = JsonConvert.SerializeObject( new DateTime( 1970, 1, 1, 0, 0, 0, DateTimeKind.Utc ), settings );
object o = JsonConvert.DeserializeObject( s, settings ); //s = "{\"$type\":\"System.DateTime, mscorlib\",\"ticks\":0}" //ERROR OCCURS HERE
问题似乎与反序列化一个裸露的日期有关。当日期包装在另一个对象中时,它似乎起作用。这段代码适用于我:
public class Program
{
public static void Main(string[] args)
{
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
settings.PreserveReferencesHandling = PreserveReferencesHandling.All;
settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
settings.ConstructorHandling = ConstructorHandling.Default;
settings.TypeNameHandling = TypeNameHandling.All;
settings.TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
settings.DateParseHandling = DateParseHandling.DateTime;
settings.Converters.Add(new AS3DateTimeConverter());
TestObject obj = new TestObject { Date = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) };
string s = JsonConvert.SerializeObject(obj, settings);
Console.WriteLine(s);
object o = JsonConvert.DeserializeObject(s, settings);
Console.WriteLine(((TestObject)o).Date.ToString());
}
}
public class TestObject
{
public DateTime Date { get; set; }
}
public class AS3DateTimeConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTime);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JObject jo = new JObject();
jo.Add("$type", "System.DateTime, mscorlib");
jo.Add("ticks", ((DateTime)value).Ticks);
jo.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
return new DateTime(jo["ticks"].Value<long>());
}
}
输出:
{"$id":"1","$type":"Q20224027.TestObject, JsonTest","Date":{"$type":"System.DateTime, mscorlib","ticks":621355968000000000}}
1/1/1970 12:00:00 AM
更新
为了测试是否为带有嵌入类型信息的自定义顶级对象调用转换器的理论,我为date wrapper对象创建了一个转换器,并将其序列化。这起作用了,但前提是我使用deserializeObject
而不是deserializeObject
给出提示。代码如下:
namespace Q20224027
{
public class Program
{
public static void Main(string[] args)
{
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
settings.PreserveReferencesHandling = PreserveReferencesHandling.All;
settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
settings.ConstructorHandling = ConstructorHandling.Default;
settings.TypeNameHandling = TypeNameHandling.All;
settings.TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
settings.DateParseHandling = DateParseHandling.DateTime;
settings.Converters.Add(new DateWrapperConverter());
DateWrapper obj = new DateWrapper { Date = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) };
string s = JsonConvert.SerializeObject(obj, settings);
Console.WriteLine(s);
object o = JsonConvert.DeserializeObject<DateWrapper>(s, settings);
Console.WriteLine(((DateWrapper)o).Date.ToString());
}
}
public class DateWrapper
{
public DateTime Date { get; set; }
}
public class DateWrapperConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateWrapper);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
DateWrapper obj = (DateWrapper)value;
JObject jo = new JObject();
jo.Add("$type", typeof(DateWrapper).AssemblyQualifiedName);
jo.Add("ticks", obj.Date.Ticks);
jo.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
return new DateWrapper { Date = new DateTime(jo["ticks"].Value<long>()) };
}
}
}
输出:
{"$type":"Q20224027.DateWrapper, JsonTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","ticks":621355968000000000}
1/1/1970 12:00:00 AM