为什么XmlSerializer的Deserialize()吐出一个子对象,这是一个XmlNode ?

我正在使用XmlSerializer序列化然后反序列化一个简单的对象。 当我反对反序列化对象时,我发现一个子对象没有被正确地反序列化,而是变成了XmlNode[]

这里几乎是我得到的结构:

 // This line I put in here as a way of sneaking into the XML the // root node's C# namespace, since it's not the same as the // deserializing code and the deserializing code seemed unable to // deserialize properly without knowing the Type (see my code below). // So I basically just use this fake construct to get the namespace // and make a Type of it to feed the XmlSerializer() instantiation. [XmlRoot(Namespace = "http://foo.com/CSharpNamespace/Foo.Bar")] // This is because QueuedFile can be given to the Argument array. [XmlInclude(typeof(QueuedFile))] // This class is Foo.Bar.CommandAndArguments public class CommandAndArguments { public String Command; public object[] Arguments; } // I don't think this matters to XmlSerialize, but just in case... [Serializable()] // I added this line just thinking maybe it would help, but it doesn't // do anything. I tried it without the XmlType first, and that // didn't work. [XmlType("Foo.Baz.Bat.QueuedFile")] // This class is Foo.Baz.Bat.QueuedFile (in a different c# // namespace than CommandAndArguments and the deserializing code) public QueuedFile { public String FileName; public String DirectoryName; } 

反序列化它的代码看起来像:

 public static object DeserializeXml(String objectToDeserialize) { String rootNodeName = ""; String rootNodeNamespace = ""; using (XmlReader xmlReader = XmlReader.Create(new StringReader(objectToDeserialize))) { if (xmlReader.MoveToContent() == XmlNodeType.Element) { rootNodeName = xmlReader.Name; rootNodeNamespace = xmlReader.NamespaceURI; if (rootNodeNamespace.StartsWith("http://foo.com/CSharpNamespace/")) { rootNodeName = rootNodeNamespace.Substring("http://foo.com/CSharpNamespace/".Length) + "." + rootNodeName; } } } //MessageBox.Show(rootNodeName); try { Type t = DetermineTypeFromName(rootNodeName); if (t == null) { throw new Exception("Could not determine type of serialized string. Type listed as: "+rootNodeName); } var s = new XmlSerializer(t); return s.Deserialize(new StringReader(objectToDeserialize)); // object o = new object(); // MethodInfo castMethod = o.GetType().GetMethod("Cast").MakeGenericMethod(t); // return castMethod.Invoke(null, new object[] { s.Deserialize(new StringReader(objectToDeserialize)) }); } catch (InvalidOperationException) { return null; } } 

这是CommandAndArguments序列化时的XML:

   I am a command   HelloWorld.txt C:\foo\bar    

但是当我反序列化时,我得到一个CommandAndArguments对象,其中Arguments是XmlNode[] ,第一项是赋予QueuedFile类型的属性,其他索引是属性的元素。 但为什么不重新创建QueuedFile对象?

我怀疑这可能以某种方式与C#名称空间和反序列化无法找到或使用QueuedFile …但我不明白为什么因为当我忘记了XmlInclude()它确保告诉我它没想到QueuedFile ,现在我已经添加了XmlInclude()我没有错误,只是一个不完整的反序列化。

救命? 我已经阅读了所有可以阅读的内容,并将我知道的所有内容用Google搜索到了Google并且卡住了。 我当然有很多关于XML序列化的知识,但我不确定我是如何失败的,这应该是非常简单的(我实际上做了几乎完全没有任何问题的事情,唯一不同的是,一切都是在同一个C#名称空间中)。

您是否能够更改XML格式或是否已修复? 我不知道你遇到的问题是什么,但我广泛使用DataContractSerializer类没有任何问题。

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx

 public static void WriteObject(string fileName) { Console.WriteLine( "Creating a Person object and serializing it."); Person p1 = new Person("Zighetti", "Barbara", 101); FileStream writer = new FileStream(fileName, FileMode.Create); DataContractSerializer ser = new DataContractSerializer(typeof(Person)); ser.WriteObject(writer, p1); writer.Close(); } public static void ReadObject(string fileName) { Console.WriteLine("Deserializing an instance of the object."); FileStream fs = new FileStream(fileName, FileMode.Open); XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas()); DataContractSerializer ser = new DataContractSerializer(typeof(Person)); // Deserialize the data and read it from the instance. Person deserializedPerson = (Person)ser.ReadObject(reader, true); reader.Close(); fs.Close(); Console.WriteLine(String.Format("{0} {1}, ID: {2}", deserializedPerson.FirstName, deserializedPerson.LastName, deserializedPerson.ID)); } 

对于遇到类似问题的任何人,根据您的情况,您最好使用NetDataContractSerializer。 它是DataContractSerializer的替代品,它可以在XML中记录.Net类型,使反序列化变得轻而易举,因为它确切地知道涉及哪些类型,因此您不需要使用deserialize命令告诉它根对象的类型。 它可以以XML或二进制forms生成输出(我更喜欢XML以便于调试)。

下面是一些示例代码,用于轻松地将对象序列化和反序列化为字符串:

 private static object Deserialize(string xml) { object toReturn = null; using (Stream stream = new MemoryStream()) { byte[] data = System.Text.Encoding.UTF8.GetBytes(xml); stream.Write(data, 0, data.Length); stream.Position = 0; var netDataContractSerializer = new NetDataContractSerializer(); toReturn = netDataContractSerializer.Deserialize(stream); } return toReturn; } private static string Serialize(object obj) { using (var memoryStream = new MemoryStream()) using (var reader = new StreamReader(memoryStream)) { var netDataContractSerializer = new NetDataContractSerializer(); netDataContractSerializer.Serialize(memoryStream, obj); memoryStream.Position = 0; return reader.ReadToEnd(); } } 

非常简单!