2012-02-13 49 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

相關問題