我想序列化和反序列化Nullable DateTime到/从JSON,但我不想用JsonConverterAttribute注释它。然而,我想把它放在JsonSerializerSettings中的一个地方,而不是用这些属性使dto像往常一样干净。
这里是DTO:
public class Post
{
public DateTime? Created { get; set; }
}
这里是自定义JsonConverter:
internal class EpochDateTimeConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(DateTime).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var t = (long)Convert.ToDouble(reader.Value.ToString());
return t.FromUnixTime();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
long ticks;
DateTime valueAsDate = (DateTime)value;
if (valueAsDate != DateTime.MinValue)
{
if (value is DateTime)
{
var epoc = new DateTime(1970, 1, 1);
var delta = (valueAsDate) - epoc;
if (delta.TotalSeconds < 0)
{
throw new ArgumentOutOfRangeException("Unix epoc starts January 1st, 1970");
}
ticks = (long)delta.TotalSeconds;
}
else
{
throw new Exception("Expected date object value.");
}
writer.WriteValue(ticks);
}
}
}
这是最小的复制:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace NameSpaceSample
{
public class Post
{
public DateTime? Created { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
var settings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
Converters = new List<JsonConverter>
{
new EpochDateTimeConverter()
}
};
string postAsJson = JsonConvert.SerializeObject(new Post { Created = DateTime.UtcNow }, settings);
Console.WriteLine(postAsJson);// {"Created":"2015-09-17T17:15:06.6160689Z"}
var json = "{"Created":1442510191}";
Post post = JsonConvert.DeserializeObject<Post>(json, settings);//Exception here
Console.ReadKey();
}
}
}
该行抛出的异常是:
JsonReaderException:
Error reading date. Unexpected token: Integer. Path 'Created', line 1, position 21.
注意:
我知道这可以通过用JsonConverterAttribute注释它来解决,但我不想这样做,因为前面提到的原因。
public class Post
{
[JsonConverter(typeof(EpochDateTimeConverter))]
public DateTime? Created { get; set; }
}
我自己想出来的。我只需要改变CanConvert
函数如下:
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTime) || objectType == typeof(DateTime?);
}
这不是很容易找到。把我的答案放在这里,以帮助其他人,如果他们遇到这样的问题。
我给你从一个对象到另一个对象的方式,这样你就不用担心转移任何东西,谢谢
public static T ConvertTo<T>(this object value)
{
T returnValue = default(T);
if (value is T)
{
returnValue = (T)value;
}
else
{
try
{
returnValue = (T)Convert.ChangeType(value, typeof(T));
}
catch (InvalidCastException)
{
returnValue = default(T);
}
}
return returnValue;
}
JsonConverter
的CanConvert(Type objectType)
方法决定该转换器是否将用于正在序列化/反序列化的当前属性。
由于您的属性类型是DateTime?
,并且不能从DateTime
分配,它返回false,然后不使用转换器。
你只需要改变方法如下:
public override bool CanConvert(Type objectType)
{
return typeof(DateTime?).IsAssignableFrom(objectType);
}