using System;
using System.Runtime.Serialization;
using System.Xml;
using System.IO;
using System.Collections.Generic;
[DataContract(Name = "Book", Namespace = "")]
public class Book
{
[DataMember] public string Title { get; set; }
[DataMember] public string Author { get; set; }
[DataMember] public int Year { get; set; }
}
[DataContract(Name = "Library", Namespace = "")]
public class Library
{
[DataMember] public string Name { get; set; }
[DataMember] public List<Book> Books { get; set; }
}
public class Program
{
static string xml = @"<?xml version=""1.0"" encoding=""utf-8""?>
<Library xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
<Name>Central Library</Name>
<Books>
<Book>
<Title>The Great Gatsby</Title>
<Author>F. Scott Fitzgerald</Author>
<Year>1925</Year>
</Book>
<Book>
<Title>To Kill a Mockingbird</Title>
<Author>Harper Lee</Author>
<Year>1960</Year>
</Book>
</Books>
</Library>";
static void Main(string[] args)
{
try
{
Library library = DeserializeLibrary(xml);
Console.WriteLine($"Deserialized Library: {library.Name}");
foreach (var book in library.Books)
{
Console.WriteLine($"Book: {book.Title} by {book.Author} ({book.Year})");
}
}
catch (Exception e)
{
Console.WriteLine($"Deserialization failed: {e.Message}");
Console.WriteLine($"Stack trace: {e.StackTrace}");
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
/// <summary>
/// Deserializes the XML string into a Library object using DataContractSerializer
/// </summary>
static Library DeserializeLibrary(string xmlString)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Library));
using (StringReader stringReader = new StringReader(xmlString))
using (XmlReader xmlReader = XmlReader.Create(stringReader))
{
return (Library)serializer.ReadObject(xmlReader);
}
}
}
反序列化库:中央库 反序列化失败:未将对象引用设置为对象的实例 堆栈跟踪:位于 Program.Main (System.String[] args) [0x0002a] in :0
我一直遇到这个问题,但我不知道为什么。我读了一遍又一遍的手册,但没有解决。我如何才能正确序列化此图书列表?
注意,我已经查看了WCF:序列化和反序列化通用集合,但建议的更改都没有解决该问题。只有一个解决方案可以解决此问题,即将 XML 中的一个元素移至下方:
<?xml version=""1.0"" encoding=""utf-8""?>
<Library
xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
<Books>
<Book>
<Title>The Great Gatsby</Title>
<Author>F. Scott Fitzgerald</Author>
<Year>1925</Year>
</Book>
<Book>
<Title>To Kill a Mockingbird</Title>
<Author>Harper Lee</Author>
<Year>1960</Year>
</Book>
</Books>
<Name>Central Library</Name>
</Library>
这没有任何意义,因为 Microsoft 自己的文档中没有提到排序。
它应该打印书籍列表
我用这个修复了它,例如:
public class Library {
[DataMember(Order = 0)] public string Name { get; set; }
[DataMember(Name = "Books", Order = 1)]
public List<Book> books = new();
public List<Book> Books => books;
}
现在它可以正确读取代码示例中的原始 XML 字符串。
问题是您的 XML 字符串与您的数据契约不对应。在 XML 中,
Name
是 Library
中的第一个元素,如果您将其移到 Books
之后,它将与您未修改的数据协定一起使用。
就是这样。您可以决定如何处理每种情况下的排序,是否避免使用
Order
参数。不管怎样,我强烈建议您至少首先使用 serializer.WriteObject
创建一个全面的 XML 数据示例。您可以将示例对象图写入文件,然后手动写入输入 XML(如果您需要的话)。
此外,我还演示了当
Books
永远不是 null
时的模式。这是正确实现对象composition或aggregation的方法。我认为您从未想象过当 Books
永远是 null
时的情况,如果它非空但为空或不为空,那就有意义。在原始代码中,您每次都需要创建一个 Book
实例,但这没有意义。
代码的另一个问题是没有为数据契约定义命名空间名称。您最好确保对同一个合约使用相同的名称,否则,XML 将在对象图的根内部获得冗余的命名空间。所以,你可以做类似的事情
static class DefinitionSet {
internal const string dataContractNamespace =
"https/www.my.site.org/contracts/library";
//...
}
[DataContract(
Name = "Book",
Namespace = DefinitionSet.dataContractNamespace)]
public class Book { /* ... */ }
[DataContract(
Name = "Book",
Namespace = DefinitionSet.dataContractNamespace)]
public class Library { /* ... */ }
这对于合约的身份和唯一性、维护和版本控制非常重要。有一个空的命名空间很好,但不适合实际生产。