2013-07-23 35 views
1

如何转换具有递归类型的对象(不是对象,只是类型)?以下代码在尝试序列化具有父/子关系的对象时失败。如何将递归类型转换为JSON

错误是最后一次调用ser.WriteObject(stream1,parent);抛出该异常:

System.Runtime.Serialization.SerializationException was unhandled 
  HResult=-2146233076 
  Message=Type 'TestJson.Child' with data contract name 'Child:http://schemas.datacontract.org/2004/07/TestJson' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer. 
  Source=System.Runtime.Serialization 
  StackTrace: 
       at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) 
       at System.Runtime.Serialization.Json.XmlObjectSerializerWriteContextComplexJson.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType) 
       at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) 
       at System.Runtime.Serialization.XmlObjectSerializerWriteContextComplex.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) 
       at WriteArrayOfPersonToJson(XmlWriterDelegator , Object , XmlObjectSerializerWriteContextComplexJson , CollectionDataContract) 
       at System.Runtime.Serialization.Json.JsonCollectionDataContract.WriteJsonValueCore(XmlWriterDelegator jsonWriter, Object obj, XmlObjectSerializerWriteContextComplexJson context, RuntimeTypeHandle declaredTypeHandle) 
       at System.Runtime.Serialization.Json.XmlObjectSerializerWriteContextComplexJson.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) 
       at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) 
       at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) 
       at System.Runtime.Serialization.XmlObjectSerializerWriteContextComplex.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) 
       at WriteAdultToJson(XmlWriterDelegator , Object , XmlObjectSerializerWriteContextComplexJson , ClassDataContract , XmlDictionaryString[]) 
       at System.Runtime.Serialization.Json.JsonClassDataContract.WriteJsonValueCore(XmlWriterDelegator jsonWriter, Object obj, XmlObjectSerializerWriteContextComplexJson context, RuntimeTypeHandle declaredTypeHandle) 
       at System.Runtime.Serialization.Json.XmlObjectSerializerWriteContextComplexJson.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) 
       at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) 
       at System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph) 
       at System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph) 
       at System.Runtime.Serialization.XmlObjectSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) 
       at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) 
       at System.Runtime.Serialization.Json.DataContractJsonSerializer.WriteObject(XmlDictionaryWriter writer, Object graph) 
       at System.Runtime.Serialization.Json.DataContractJsonSerializer.WriteObject(Stream stream, Object graph) 
       at TestJson.Program.Main(String[] args) in c:\src\TestJson\Program.cs:line 44 
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
       at System.Threading.ThreadHelper.ThreadStart() 
  InnerException: 

完整的代码是:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Json; 

namespace TestJson 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Adult parent = new Adult {name = "John", age = 42}; 

      MemoryStream stream1 = new MemoryStream(); 
      DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Adult)); 
      ser.WriteObject(stream1, parent); 

      stream1.Position = 0; 
      StreamReader sr = new StreamReader(stream1); 
      Console.Write("JSON form of Adult with no children: "); 
      Console.WriteLine(sr.ReadToEnd()); 


      Child child = new Child { name = "Jane", age = 4, fingers=10 }; 

      stream1 = new MemoryStream(); 
      ser = new DataContractJsonSerializer(typeof(Child)); 
      ser.WriteObject(stream1, child); 

      stream1.Position = 0; 
      sr = new StreamReader(stream1); 
      Console.Write("JSON form of Child with no parent: "); 
      Console.WriteLine(sr.ReadToEnd()); 


      // now connect the two 
      parent.children.Add(child); 

      stream1 = new MemoryStream(); 
      ser = new DataContractJsonSerializer(typeof(Adult)); 
      ser.WriteObject(stream1, parent); 

      stream1.Position = 0; 
      sr = new StreamReader(stream1); 
      Console.Write("JSON form of Adult with 1 child: "); 
      Console.WriteLine(sr.ReadToEnd()); 
     } 
    } 

    [DataContract] 
    class Person 
    { 
     [DataMember] 
     internal string name; 

     [DataMember] 
     internal int age; 
    } 

    [DataContract] 
    class Adult : Person 
    { 
     [DataMember] 
     internal List<Person> children = new List<Person>(); 
    } 

    [DataContract] 
    class Child : Person 
    { 
     [DataMember] 
     internal int fingers; 
    } 
} 
+1

它究竟做了什么?它如何失败?你期望发生什么以及发生了什么? –

+0

@DanielHilgarth有没有不明类型。问题在于声明中的递归类型。 –

+0

@DavidThielen:是的,有未知的类型。请看我的回答,并在那里添加更多评论,因为我在这里删除了我的评论。 –

回答

1

只需按照异常消息给出的建议和KnownType属性添加到Person

[DataContract] 
[KnownType(typeof(Parent))] 
[KnownType(typeof(Child))] 
class Person 
{ 
    [DataMember] 
    internal string name; 

    [DataMember] 
    internal int age; 
} 

您需要主动通过基类上的KnownType属性使序列化引擎知道派生类型。
您的问题与无关递归对象。

+0

有没有什么办法让它不在属性中包含“__type”:“Child:#TestJson”?我们有些情况下我们会在REST获得数百个这样的数据,并且会加起来。 –

+0

@DavidThielen:我想这将是一个新问题。换句话说:我不知道;-)然而,问题是:反序列化部分如何知道它处理的是什么类型? –