【问题标题】:DataContractJsonSerializer - Deserializing DateTime within List<object>DataContractJsonSerializer - 在 List<object> 中反序列化 DateTime
【发布时间】:2012-02-13 19:10:23
【问题描述】:

我在使用 System.Runtime.Serialization.Json.DataContractJsonSerializer 类反序列化 List&lt;object&gt; 中包含的 DateTime 实例时遇到问题。我似乎无法让 DateTime 反序列化回原始类型。 DataContractJsonSerializer 总是将其反序列化为格式为"/Date(1329159196126-0500)/" 的字符串类型。如果我使用强类型的List&lt;DateTime&gt; 运行它,它将很好地序列化和反序列化,但是我正在寻找让序列化程序在object 的简单列表或数组中遇到时识别并正确反序列化 DateTimes 的方法。

请注意,除了原语和字符串之外,此列表将永远包含 DateTimes 类型。 这是我用来测试的代码 sn-p。

var list = new List<object> { 27, "foo bar", 12.34m, true, DateTime.Now };
var serializer = new DataContractJsonSerializer(typeof (List<object>));
using (MemoryStream ms = new MemoryStream())
{
    serializer.WriteObject(ms, list);
    ms.Position = 0;
    var deserializedList = serializer.ReadObject(ms) as List<object>;
}

【问题讨论】:

  • 您应该考虑将接受的答案更改为获得 40 票赞成的答案。

标签: c# json datacontractjsonserializer


【解决方案1】:

在 .NET Framework 4.5 版中,DataContractJsonSerializer 有一个构造函数,该构造函数接受可用于设置 DateTimeFormat 的 DataContractJsonSerializerSettings 对象:

var ser = new DataContractJsonSerializer(typeof(CreateOmsEntryCommand),
              new DataContractJsonSerializerSettings
              {
                  DateTimeFormat = new DateTimeFormat("yyyy-MM-dd'T'HH:mm:ssZ")
              });

【讨论】:

  • 就序列化而言,如果 DateTime 首先不是 UTC,这似乎不起作用:它将具有本地时间的值,但使用 Z代表 UTC(所以在阅读方面会被误解)。改用yyyy-MM-dd'T'HH:mm:ssK 可能会更好。
  • 我同意,请使用yyyy-MM-dd'T'HH:mm:ssK 或yyyy-MM-dd'T'HH:mm:sszzz。不要使用yyyy-MM-dd'T'HH:mm:ssZ。
【解决方案2】:

这似乎是一种非常奇怪的行为,我的猜测是它源于 DateTime 不是 JSON 中可识别的类型。但是,您可以滚动自己的 IDataContractSurrogate 来修改序列化/反序列化过程。

要使用它,请在创建序列化程序时修改您的示例代码:

var serializer = new DataContractJsonSerializer(typeof(List<object>), null, int.MaxValue, false, new DateTimeDataContractSurrogate(), true);

然后添加这个类:

public class DateTimeDataContractSurrogate : IDataContractSurrogate
    {
        private static readonly Regex dateRegex = new Regex(@"/Date\((\d+)([-+])(\d+)\)/");
        private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

        public object GetCustomDataToExport(Type clrType, Type dataContractType)
        {
            // not used
            return null;
        }

        public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
        {
            // not used
            return null;
        }

        public Type GetDataContractType(Type type)
        {
            // not used
            return type;
        }

        public object GetDeserializedObject(object obj, Type targetType)
        {
            // for debugging
            //Console.WriteLine("GetDeserializedObject: obj = {0} ({1}), targetType = {2}", obj, obj.GetType(), targetType);

            // only act on List<object> types
            if (obj.GetType() == typeof(List<object>))
            {
                var objList = (List<object>)obj;

                List<object> copyList = new List<object>(); // a list to copy values into. this will be the list returned.
                foreach (var item in objList)
                {
                    string s = item as string;
                    if (s != null)
                    {
                        // check if we match the DateTime format
                        Match match = dateRegex.Match(s);
                        if (match.Success)
                        {
                            // try to parse the string into a long. then create a datetime and convert to local time.
                            long msFromEpoch;
                            if (long.TryParse(match.Groups[1].Value, out msFromEpoch))
                            {
                                TimeSpan fromEpoch = TimeSpan.FromMilliseconds(msFromEpoch);
                                copyList.Add(TimeZoneInfo.ConvertTimeFromUtc(epoch.Add(fromEpoch), TimeZoneInfo.Local));
                                continue;
                            }
                        }
                    }

                    copyList.Add(item); // add unmodified
                }

                return copyList;
            }

            return obj;
        }

        public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes)
        {
            // not used   
        }

        public object GetObjectToSerialize(object obj, Type targetType)
        {
            // for debugging
            //Console.WriteLine("GetObjectToSerialize: obj = {0} ({1}), targetType = {2}", obj, obj.GetType(), targetType);
            return obj;
        }

        public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
        {
            // not used
            return null;
        }

        public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
        {
            // not used
            return typeDeclaration;
        }
    }

【讨论】:

  • 这基本上是我最终实施的解决方案。谢谢。
  • 为了支持 1970 年之前的日期,您的正则表达式应为 /Date\((-?\d+)([-+])(\d+)\)/)
【解决方案3】:

如果DataContractJsonSerializer 不是必须,这里是使用Json.Net 的解决方案。

var list = new List<object> { 27, "foo bar", 12.34m, true, DateTime.Now };

string json = JsonConvert.SerializeObject(list);
var orgObj=JsonConvert.DeserializeObject<List<object>>(json);

这是 Json 字符串

[27,"foo bar",12.34,true,"\/Date(1329161615596+0200)\/"]

返回类型为long,string,double,bool 和DateTime

【讨论】:

    【解决方案4】:

    您可以在序列化之前将 DateTime.Now 转换为字符串,并且
    反序列化后将其转换回 DateTime。

    通过以下方式转换为字符串:

    string dateAsString = Convert.ToString(DateTime.Now);
    

    反序列化后转换回DateTime:

    DateTime dateTime = Convert.ToDateTime(deserializedList[4]);
    

    所以整个代码应该是这样的:

      string dateAsString = Convert.ToString(DateTime.Now);
      var list = new object[] { 27, "foo bar", 12.34m, true, dateAsString };
    
      var serializer = new DataContractJsonSerializer(typeof (List<object>));
    
      using (MemoryStream ms = new MemoryStream())
      {
        serializer.WriteObject(ms, list);
        ms.Position = 0;
        var deserializedList = serializer.ReadObject(ms) as List<object>;
        DateTime dateTime = Convert.ToDateTime(deserializedList[4]);
      }
    

    【讨论】:

      猜你喜欢
      • 2019-05-07
      • 1970-01-01
      • 1970-01-01
      • 2013-09-23
      • 1970-01-01
      • 2021-06-14
      • 2018-01-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多