[英]XmlSerializer.Deserialize() isn't deserializing a List<T> correctly
我是C#XmlSerializer的新手,所以我可能会遗漏一些基本的东西。
我遇到的问题是我有一个类有另一个类的List<T>
。 当我序列化主类时,XML看起来很漂亮,所有数据都完好无损。 当我反序列化XML时, List<T>
的数据消失了,我留下了一个空的List<T>
。 我没有收到任何错误,序列化部分就像魅力一样。
反序列化过程中我错过了什么?
编辑:请注意,下面显示的代码不会重现问题 - 它的工作原理。 这是真正的代码, 没有工作的简化版本。 不幸的是,下面的代码已经足够简化,无法重现问题!
public class User
{
public User()
{
this.Characters = new List<Character>();
}
public string Username { get; set; }
public List<Character> Characters { get; set; }
}
public class Character
{
public Character()
{
this.Skills = new List<Skill>();
}
public string Name { get; set; }
public List<Skill> Skills { get; set; }
}
public enum Skill
{
TreeClimber,
ForkliftOperator
}
public static void Save(User user)
{
using (var textWriter = new StreamWriter("data.xml"))
{
var xmlSerializer = new XmlSerializer(typeof(User));
xmlSerializer.Serialize(textWriter, user);
}
}
public static User Restore()
{
if (!File.Exists("data.xml"))
throw new FileNotFoundException("data.xml");
using (var textReader = new StreamReader("data.xml"))
{
var xmlSerializer = new XmlSerializer(typeof(User));
return (User)xmlSerializer.Deserialize(textReader);
}
}
public void CreateAndSave()
{
var character = new Character();
character.Name = "Tranzor Z";
character.Skills.Add(Skill.TreeClimber);
var user = new User();
user.Username = "Somebody";
user.Characters.Add(character);
Save(user);
}
public void RestoreAndPrint()
{
var user = Restore();
Console.WriteLine("Username: {0}", user.Username);
Console.WriteLine("Characters: {0}", user.Characters.Count);
}
通过执行CreateAndSave()生成的XML如下所示:
<User>
<Username>Somebody</Username>
<Characters>
<Character>
<Name>Tranzor Z</Name>
<Skills>
<Skill>TreeClimber</Skill>
</Skills>
</Character>
<Characters>
</User>
完善! 这就是应该看的样子。 如果我然后执行RestoreAndPrint()
我得到一个User对象,其Username属性设置正确但Characters属性是一个空列表:
Username: Somebody
Characters: 0
任何人都可以向我解释为什么Characters属性被正确序列化但不会反序列化?
无法重现; 我得到(在修复更直接的错误之后):
Username: Somebody
Characters: 1
变化:
WriteLine
而不是WriteFormat
(阻止它编译) CreateAndSave
工作):
public User() { Characters = new List<Character>(); }
public Character() { Skills = new List<Skill>(); }
过去,在序列化列表时,我使用了[XmlArray]和[XmlArrayItem]注释。 然后,您将在Characters属性上放置一个[XmlIgnore]注释。 在你的情况下,它看起来像这样:
[XmlArray("Characters")]
[XmlArrayItem("Character", Type=typeof(Character))]
public Character[] _ Characters
{
get
{
//Make an array of Characters to return
return Characters.ToArray();
}
set
{
Characters.Clear();
for( int i = 0; i < value.Length; i++ )
Characters.Add( value[i] );
}
}
希望有所帮助。
我知道这是旧的,但我有同样的问题。
我发现如果我有一个在图中实现IXmlSerializable的对象(所以我想反序列化的主要对象不实现接口,但是它中的一个对象实现它),它会破坏所有的反序列化。 列表不再反序列化,也不是我正在谈论的对象。 序列化工作完美。
也许,而不是StreamReader,而是创建一个XmlReader。 此外,作为故障排除步骤,您可以尝试使用显式类型(如下所示)而不是“var”声明的现有代码。
public static User Restore()
{
if (!File.Exists("data.xml"))
throw new FileNotFoundException("data.xml");
XmlReader xr = XmlReader.Create("data.xml");
XmlSerializer serializer = new XmlSerializer(typeof(User));
var user = (User)serializer.Deserialize(xr);
xr.Close();
return user;
}
编辑:此外,尝试在您的User类上的XmlInclude批注。
[XmlInclude( typeof( Character ) )]
在对代码进行了很长时间的讨论之后,我终于放弃了使用XmlSerializer的默认行为的想法。
所有相关类现在都继承IXmlSerializer并实现ReadXml()和WriteXml()函数。 我真的希望采取懒惰的路线,但现在我已经玩过IXmlSerializer,我意识到它真的不难,增加的灵活性非常好。
我将此属性添加到我的List类型,然后它工作了(有同样的问题):
[System.Xml.Serialization.XmlElementAttribute("NameOfMyField")]
public List<SomeType> NameOfMyField{get;set;}
我认为这是你的解决方案。
Stream stream = File.Open(filename + ".xml", FileMode.Open);
User user = null;
using (XmlReader reader = XmlReader.Create(stream))
{
user = IntermediateSerializer.Deserialize<User>(reader, null);
}
stream.Close();
return user;
我会尝试使用这样的东西。
它可能与enum的反序列化有关....因为它将它序列化为字符串值...可能无法为字符创建正确的枚举值。 没有测试过这个假设......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.