2012-02-13 29 views
8

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

请注意,除了此列表将包含的基本字符和字符串之外,DateTimes是唯一的类型。 这里是我用来测试这个代码片段。

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>; 
} 

回答

7

这似乎是很奇怪行为,我的猜测是,它源于DateTime不是一个在JS中被识别的类型上。但是,您可以滚动您自己的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; 
     } 
    } 
+1

这实际上是我最终实现的解决方案。谢谢。 – 2012-02-21 14:16:09

+0

为了支持1970年之前的日期,你的正则表达式应该是'/ Date \(( - ?\ d +)([ - +])(\ d +)\)/)' – 2015-07-21 15:47:30

4

如果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)\/"] 

,返回类型是longstringdoubleboolDateTime

3

你可以DateTime.Now转换为字符串串行化之前和
将其转换回DateT反序列化后的ime

转换为字符串由:

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

转换回日期时间反序列化后:

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]); 
    } 
30

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

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

就序列化而言,如果'DateTime'首先不是UTC,那么这似乎不起作用:的当地时间,但是以'Z'表示UTC(所以在读取侧被误解)。最好使用'yyyy-MM-dd'T'HH:mm:ssK'代替。 – Bruno 2016-09-27 16:08:45

+1

我同意,使用'yyyy-MM-dd'T'HH:mm:ssK'或'yyyy-MM-dd'T'HH:mm:sszzz'。不要使用'yyyy-MM-dd'T'HH:mm:ssZ'。 – 2017-06-25 17:22:09

相关问题