C# XmlSerializer.Deserialize() 未正确反序列化 List<T>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/890316/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 08:36:32  来源:igfitidea点击:

XmlSerializer.Deserialize() isn't deserializing a List<T> correctly

c#.netxml-serialization

提问by Andy

I am new to the C# XmlSerializer so I might be missing something basic here.

我是 C# XmlSerializer 的新手,所以我可能在这里遗漏了一些基本的东西。

The problem I am running into is that I have one class that has a List<T>of another class. When I serialize the main class the XML looks beautiful and all the data is intact. When I deserialize the XML, the data in the List<T>disappears and I am left with an empty List<T>. I am not receiving any errors and the serialization portion works like charm.

我遇到的问题是我有一个班级有List<T>另一个班级。当我序列化主类时,XML 看起来很漂亮,所有数据都完好无损。当我反序列化 XML 时,其中的数据List<T>消失了,只剩下一个空的List<T>. 我没有收到任何错误,序列化部分就像魅力一样。

What am I missing with the deserialization process?

我在反序列化过程中遗漏了什么?

EDIT:Note that the code shown below does not reproduce the problem - it works. This was a simplified version of the real code, which did notwork. Unfortunately, the code below was simplified enough to not reproduce the problem!

编辑:请注意,下面显示的代码不会重现该问题 - 它有效。这是真正的代码,并简化版本无法正常工作。不幸的是,下面的代码已经简化到无法重现问题!

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);
}

The XML generated by executing CreateAndSave() looks like so:

通过执行 CreateAndSave() 生成的 XML 如下所示:

<User>
  <Username>Somebody</Username>
  <Characters>
    <Character>
      <Name>Tranzor Z</Name>
      <Skills>
        <Skill>TreeClimber</Skill>
      </Skills>
    </Character>
  <Characters>
</User>

Perfect! That's the way it should look. If I then execute RestoreAndPrint()I get a User object with the Username property set properly but the Characters property is an empty list:

完美的!这就是它应该看起来的样子。如果我然后执行,RestoreAndPrint()我会得到一个 User 对象,其 Username 属性设置正确,但 Characters 属性是一个空列表:

Username: Somebody
Characters: 0

Can anybody explain to me why the Characters property is serialized properly but won't deserialize?

任何人都可以向我解释为什么 Characters 属性被正确序列化但不会反序列化?

采纳答案by Andy

After futzing around with the code for a long time I finally gave up on the idea of using the default behaviour of the XmlSerializer.

在对代码折腾了很长时间之后,我终于放弃了使用 XmlSerializer 的默认行为的想法。

All of the relevant classes now inherit IXmlSerializer and implement the ReadXml() and WriteXml() functions. I was really hoping to take the lazy route but now that I've played with IXmlSerializer I realize that it really isn't difficult at all and the added flexibility is really nice.

所有相关类现在都继承 IXmlSerializer 并实现 ReadXml() 和 WriteXml() 函数。我真的希望走懒惰的路线,但现在我已经使用了 IXmlSerializer,我意识到这真的一点都不难,而且增加的灵活性非常好。

回答by CSharpAtl

It might have to do with the deserializing of the enum....since it serialized it as the string value...might have trouble creating the correct enum value for the character. Have not tested this hypothesis...

它可能与枚举的反序列化有关......因为它将它序列化为字符串值......可能无法为字符创建正确的枚举值。没有验证过这个假设...

回答by Chris Watts

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;

I would try using something like this.

我会尝试使用这样的东西。

回答by Marc Gravell

Cannot reproduce; I get (after fixing the more immediate bugs):

无法复制;我得到(在修复更直接的错误之后):

Username: Somebody
Characters: 1

Changes:

变化:

  • WriteLineinstead of WriteFormat(which prevented it compiling)
  • init the lists in the default constructors (which prevented CreateAndSavefrom working):
    • public User() { Characters = new List<Character>(); }
    • public Character() { Skills = new List<Skill>(); }
  • WriteLine而不是WriteFormat(阻止它编译)
  • 初始化默认构造函数中的列表(阻止其CreateAndSave工作):
    • public User() { Characters = new List<Character>(); }
    • public Character() { Skills = new List<Skill>(); }

回答by Dov

In the past, when serializing lists, I've used the [XmlArray] and [XmlArrayItem] annotations. You would then put an [XmlIgnore] annotation on the Characters property. In your case, it would look something like this:

过去,在序列化列表时,我使用了 [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] );
    }
}

Hope that helps.

希望有帮助。

回答by Dov

Perhaps, instead of a StreamReader, create an XmlReader, instead. Also, as a troubleshooting step, you might try your existing code with explicit types (as below) instead of "var" declarations.

也许,而不是 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;
}

EDIT: Also, try the XmlInclude annotation on your User class.

编辑:另外,在您的 User 类上尝试 XmlInclude 注释。

[XmlInclude( typeof( Character ) )]

回答by Brady Moritz

I added this attribute to my List types and it worked then (had your same problem):

我将此属性添加到我的 List 类型中,然后它就起作用了(遇到了同样的问题):

[System.Xml.Serialization.XmlElementAttribute("NameOfMyField")]
public List<SomeType> NameOfMyField{get;set;}

I think this is your solution.

我认为这是您的解决方案。

回答by Alex1984

I know this is old but i have the same problem.

我知道这是旧的,但我有同样的问题。

What i found is that if i have an object that implements IXmlSerializable in the graph (so the main object that i want to deserialize dosen't implement the interface, but an object in it implements it), it ruins all the deserialization. Lists don't deserialize anymore, neither the object i'm talking about. Serialization works perfect.

我发现,如果我有一个在图中实现 IXmlSerializable 的对象(所以我想反序列化的主要对象没有实现接口,但其中的一个对象实现了它),它会破坏所有的反序列化。列表不再反序列化,我正在谈论的对象也不再反序列化。序列化工作完美。