gpt4 book ai didi

json - 在 .net 4.5 标准序列化程序中定义时间跨度格式

转载 作者:行者123 更新时间:2023-12-01 06:06:24 25 4
gpt4 key购买 nike

我有一个具有一些时间跨度属性的对象,我在我的 MVC 操作中使用 .net 序列化器。(我的操作返回 JsonResult 类型)timeSpan Prop 像这样反序列化:

"EndTime":{"Hours":9,"Minutes":0,"Seconds":0,"Milliseconds":0,"Ticks":324000000000,"Days":0,"TotalDays":0.375,"TotalHours":9,"TotalMilliseconds":32400000,"TotalMinutes":540,"TotalSeconds":32400}

之后我在 Windows 应用程序中调用此操作,我需要使用 newtonesoft 反序列化此对象。但我收到这个错误:

cannot deserialize the current JSON object(e.g. {"name":"value"}) into type 'system.Nullable[System.TimeSpan]' because the type requires a JSON primitivevalue (e.g. string, number, boolean, null) to deserialize correctly.To fix this error either change JSON to a JSON primitive value (e.g. string,number, boolean, null) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection typelike an array or List) that can be deserialized from JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.Path 'InTime.Hours' line 1

重要的是要知道,我的服务器项目必须只使用 microsoft .net 序列化器,而 win 应用程序必须只使用 Newtonesoft 反序列化器!

毕竟我猜,如果serializer,make name:value 问题就解决了,也许是这样的

{"EndTime":"090000"}

但我不知道如何强制序列化程序更改 TimeSpan 格式!

也许是这样的???? :-) :

public class Attendance
{
public int ID { get; set; }
public int PID { get; set; }

[Define Format in serialization here (maybe !)]
public System.TimeSpan time { get; set; }

}

最佳答案

您的服务器正在输出 TimeSpan使用 JavaScriptSerializer格式,而您的客户期望时间跨度为 Json.NET格式。

通过测试可以看到两种格式,如下:

Debug.WriteLine(new JavaScriptSerializer().Serialize(DateTime.Today - DateTime.Today.AddDays(-1)))

打印:

{"Ticks":864000000000,"Days":1,"Hours":0,"Milliseconds":0,"Minutes":0,"Seconds":0,"TotalDays":1,"TotalHours":24,"TotalMilliseconds":86400000,"TotalMinutes":1440,"TotalSeconds":86400}

对比

Debug.WriteLine(JsonConvert.SerializeObject(DateTime.Today - DateTime.Today.AddDays(-1)))

它打印的更简洁:

"1.00:00:00"

让 Json.NET 以 JavaScriptSerializer 格式解析 TimeSpan 对象会很容易,但你的要求是相反的:make JavaScriptSerializer以 Json.NET 格式输出。这更加困难,因为 Json.NET 将时间跨度表示为一个简单的字符串,但是 JavaScriptConverter只允许将类型映射到自定义 JSON 对象 -- 而不是字符串。

因此有必要将转换器应用到所有包含 TimeSpan 的类型。这是一个通用转换器,它执行默认转换,然后覆盖所有 TimeSpan 值的属性和字段。它对于较小的类(例如您的示例类)性能良好,但对于序列化大型根类的性能较差,您可能需要为此编写自定义转换器:

public class TypeWithTimespanConverter<T> : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { typeof(T) };
}
}

public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}

public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
// Use a "fresh" JavaScriptSerializer here to avoid infinite recursion.
var hasTimeSpan = (T)obj;

// Generate a default serialization. Is there an easier way to do this?
var defaultSerializer = new JavaScriptSerializer();
var dict = defaultSerializer.Deserialize<Dictionary<string, object>>(defaultSerializer.Serialize(obj));

foreach (var pair in dict.ToList())
{
if (!(pair.Value is IDictionary))
continue;
TimeSpan span;
if (obj.TryGetPropertyValueOfType<TimeSpan>(pair.Key, out span))
{
dict[pair.Key] = span.ToString();
continue;
}
TimeSpan? spanPtr;
if (obj.TryGetPropertyValueOfType<TimeSpan?>(pair.Key, out spanPtr))
{
if (spanPtr == null)
dict[pair.Key] = null;
else
dict[pair.Key] = spanPtr.Value.ToString();
continue;
}
}

return dict;
}
}

public static class ObjectExtensions
{
public static bool TryGetPropertyValueOfType<T>(this object obj, string name, out T value)
{
if (obj == null)
throw new NullReferenceException();
var type = obj.GetType();
var property = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
if (property != null
&& property.GetIndexParameters().Length == 0
&& typeof(T).IsAssignableFrom(property.PropertyType)
&& property.GetGetMethod(false) != null)
{
value = (T)property.GetGetMethod(false).Invoke(obj, new object[0]);
return true;
}

var field = type.GetField(name, BindingFlags.Public | BindingFlags.Instance);
if (field != null
&& typeof(T).IsAssignableFrom(field.FieldType))
{
value = (T)field.GetValue(obj);
return true;
}

value = default(T);
return false;
}
}

然后像这样使用它:

        var attendance = new Attendance { ID = 101, PID = -101, time = DateTime.Today - DateTime.Today.AddDays(-1).AddHours(-1) };

var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new TypeWithTimespanConverter<Attendance>() });

var json = serializer.Serialize(attendance); // Serialize with JavaScriptSerializer and TypeWithTimespanConverter
Debug.WriteLine(json); // Prints {"ID":101,"PID":-101,"time":"1.01:00:00"}
var attendance2 = JsonConvert.DeserializeObject<Attendance>(json); // Deserialize with Json.NET
Debug.Assert(attendance2.time == attendance.time); // Assert that the timespan was converted

要在 ASP.NET 服务中配置转换器,请参阅 How to: Configure ASP.NET Services in ASP.NET AJAX .

关于json - 在 .net 4.5 标准序列化程序中定义时间跨度格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31089707/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com