.NET XML序列化和空集合

5
我有一个类,其中包含一些集合,我想将此类的实例序列化为XML,而不必将集合初始化为空,并且无需实现IXmlSerializable。 我不在乎它是否创建空元素或根本不创建元素。 只要它可以在每个基于集合的属性上不必初始化集合的情况下正常工作即可。
我查看了所有可以用来装饰属性的XML属性,但没有成功。 这似乎是一个简单的事情,可以有一个元素或根本没有元素。 然后,在反序列化时,它将仅将它们保留为空或完全忽略它们。
以下是一个简单版本的类,用于解决此问题。 使用此类和默认值会导致异常“对象引用未设置为对象的实例”,因为集合为空;
public class MyClass
{
    public string Name { get; set; }
    public bool IsAlive { get; set; }
    public List<Car> Cars { get; set; }
    public List<Home> Homes { get; set; }
    public List<Pet> Pets { get; set; }

    public void ToXmlFile(string fileName)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
        TextWriter writer = new StreamWriter(fileName);
        serializer.Serialize(writer, this);
        writer.Close();
    }
}

编辑 感谢大家的帮助,问题最终在我的GetHashCode方法中,它没有正确处理null值。一旦我修复了这个问题,一切都好了。我将第一个回答者标记为正确答案。很抱歉造成困扰,但是与大家一起解决问题确实有所帮助。


什么问题?这应该可以(至少可以进行序列化和反序列化);你不喜欢的是什么行为? - Marc Gravell
我无法复现您所声称的异常。我能够按照您提供的方式对 MyClass 进行序列化和反序列化。可能还有其他问题存在? - Brian Ensink
@Brian,是其他问题,请谢谢您的快速帮助,证明这不是 XML 代码本身的问题。 :) - Rodney S. Foley
是什么导致了这个问题?我很好奇,因为我也遇到了同样的异常,但我相当确定不是序列化的问题。 - Rush Frisby
正如2010年1月27日帖子中的编辑所述,该问题是一个误导性的问题,不是由XmlSerializer引起的,而是由于我的GetHashCode重写没有正确处理null。 - Rodney S. Foley
4个回答

5
您不需要初始化集合就可以将类序列化为XML。以下是一个简单的程序示例:
class Program
{
    static void Main(string[] args)
    {
        MyClass c = new MyClass() { Name = "Test", IsAlive = true };
        XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
        using (MemoryStream ms = new MemoryStream())
        {
            serializer.Serialize(ms, c);
            Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
        }
        Console.ReadLine();
    }
}

这将会输出以下内容:
<?xml version="1.0"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Test</Name>
  <IsAlive>true</IsAlive>
</MyClass>

换句话说,null 集合属性的行为方式与任何其他 null 属性相同 - 它们根本不会被序列化(除非您更改了默认值,但我没有)。

我更新了问题,当我使用StreamWriter对文件进行操作并从类本身的ToXmlFile方法进行操作时,会出现“对象引用未设置为对象实例”的异常。定义用于通用列表的类很简单,其中只包含基元或枚举。你所说的是我期望它能够正常工作的方式,但事实并非如此。我还将使用用于序列化的代码更新该类。 - Rodney S. Foley
谢谢,问题出在别的地方,正如Brian在评论中所指出的那样。 - Rodney S. Foley

0
你提到了(反)序列化期间的异常;根据你定义问题的方式,你所拥有的应该可以正常工作。我想知道你是否确实拥有:
public class MyClass
{
    public string Name { get; set; }
    public bool IsAlive { get; set; }
    public List<Car> Cars { get; private set; }
    public List<Home> Homes { get; private set; }
    public List<Pet> Pets { get; private set; }
}

不想要公共的setter并不罕见。

然而,XmlSerializer对此非常挑剔;你需要一个公共的setter,或者(正如最近有人指出的那样)没有 setter;例如:

public class MyClass
{
    public string Name { get; set; }
    public bool IsAlive { get; set; }
    private readonly List<Car> cars = new List<Car>();
    public List<Car> Cars { get { return cars; } }
    private readonly List<Home> homes = new List<Home>();
    public List<Home> Homes { get { return homes; } }
    private readonly List<Pet> pets = new List<Pet>();
    public List<Pet> Pets { get { return pets; } }
}

0

我认为将XMLSerialization方法的返回类型设置为bool会让你以更安全的方式处理错误,而不是当前的方法:

public bool ToXmlFile(string fileName)
{
    if(fileName != "")
    {
       XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
       TextWriter writer = new StreamWriter(fileName);
       serializer.Serialize(writer, this);
       writer.Close();
       return true;
    }
    return false;
}

然后可以这样使用:

if(ToXMLFile)
{
     MessageBox.Show("Save Succesful");
}
else
(
     MessageBox.Show("Save unsuccesful");
)

这只是一个简单的例子,但我在自己的应用程序中加载或保存数据时使用了类似的方法,并且它运行良好,也是终端用户的良好视觉指示器。


0

你可以轻松地对其进行序列化,只需在 extraTypes 参数中发送 car、home 和 pet 的类型即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接