我需要(在)C#(.NET Framework 4.5.2)中将一个类序列化为XML,该XML具有带string
个键和string[]
数组值的字典属性。我在另一个问题上使用了this answer中提到的SerializableDictionary<TKey, TValue>
实现,这意味着我的属性属于SerializableDictionary<string, string[]>
类型。
将其序列化为XML文件看起来效果不错;但是,反序列化总是因System.InvalidOperationException而失败。
即使仅对字典进行反序列化也会发生这种情况。请参阅下面的MSTest单元测试,该测试可以重现问题:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using My.Namespace.Collections; // Where SerializableDictionary is defined.
using System.Xml.Serialization;
using System.IO;
using System.Linq;
namespace My.Namespace.Collections.Tests
{
/// <summary>
/// Provides unit test methods for the <see cref="SerializableDictionary{TKey, TValue}"/> class.
/// </summary>
[TestClass]
public class SerializableDictionaryTests
{
/// <summary>
/// A basic test that the <see cref="SerializableDictionary{TKey, TValue}"/> class has working
/// (de)serialization.
/// </summary>
[TestMethod]
[Timeout(100)]
public void SerializableDictionary_BasicTest()
{
// Arrange.
var sourceDictionary = new SerializableDictionary<string, string[]>();
SerializableDictionary<string, string[]> destinationDictionary;
var serializer = new XmlSerializer(typeof(SerializableDictionary<string, string[]>));
var list1 = new string[] { "apple", "banana", "pear" };
var list2 = new string[] { "carrot", "broccoli", "cauliflower", "onion" };
var list3 = new string[] { "beef", "chicken" };
sourceDictionary.Add("fruits", list1);
sourceDictionary.Add("vegetables", list2);
sourceDictionary.Add("meats", list3);
// Act.
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, sourceDictionary);
stream.Position = 0;
destinationDictionary = (SerializableDictionary<string, string[]>)serializer.Deserialize(stream);
}
// Assert.
// NOTE: We don't get this far because it crashes on the last statement above in the using block.
Assert.AreEqual(3, destinationDictionary.Keys.Count);
Assert.IsTrue(destinationDictionary.ContainsKey("fruits"));
Assert.IsTrue(destinationDictionary.ContainsKey("vegetables"));
Assert.IsTrue(destinationDictionary.ContainsKey("meats"));
Assert.AreEqual(3, destinationDictionary["fruits"].Length);
Assert.IsTrue(destinationDictionary["fruits"].Contains("apple"));
Assert.IsTrue(destinationDictionary["fruits"].Contains("banana"));
Assert.IsTrue(destinationDictionary["fruits"].Contains("pear"));
Assert.AreEqual(4, destinationDictionary["vegetables"].Length);
Assert.IsTrue(destinationDictionary["vegetables"].Contains("carrot"));
Assert.IsTrue(destinationDictionary["vegetables"].Contains("broccoli"));
Assert.IsTrue(destinationDictionary["vegetables"].Contains("cauliflower"));
Assert.IsTrue(destinationDictionary["vegetables"].Contains("onion"));
Assert.AreEqual(2, destinationDictionary["meats"].Length);
Assert.IsTrue(destinationDictionary["meats"].Contains("beef"));
Assert.IsTrue(destinationDictionary["meats"].Contains("chicken"));
}
}
}
例外是在serializer.Deserialize
电话,并显示:
Test method My.Namespace.Collections.Tests.SerializableDictionaryTests.SerializableDictionary_BasicTest threw exception:
System.InvalidOperationException: There is an error in XML document (8, 8). ---> System.InvalidOperationException: There is an error in XML document (8, 8). ---> System.InvalidOperationException: <ArrayOfString xmlns=''> was not expected.
为什么我会收到此异常,如何避免此异常?如果可能的话,我想避免仅为这一个属性使用自定义XML序列化。
编辑#1:
我制作了一个小型控制台程序,它运行上面的构造和序列化代码,然后使用FileStream
类将生成的XML写入文件。这是它的内容:
<?xml version="1.0"?>
<dictionary>
<item>
<key>
<string>fruits</string>
</key>
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>apple</string>
<string>banana</string>
<string>pear</string>
</ArrayOfString>
</value>
</item>
<item>
<key>
<string>vegetables</string>
</key>
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>carrot</string>
<string>broccoli</string>
<string>cauliflower</string>
<string>onion</string>
</ArrayOfString>
</value>
</item>
<item>
<key>
<string>meats</string>
</key>
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>beef</string>
<string>chicken</string>
</ArrayOfString>
</value>
</item>
</dictionary>
编辑#2:
经过一些额外测试后,我将测试中的TValue
声明的SerializableDictionary<TKey, TValue>
类型更改为不同的内容,并检查它是否有效,我可以确认它是否正常TValue
是string
,但如果将其设置为我的自定义可序列化类,则会产生相同的错误,即使该类使用SerializableAttribute
修饰或实现IXmlSerializable
接口。所以,问题实际上不仅仅是字符串数组。
答案 0 :(得分:1)
我很高兴您找到了解决方案,并设法使其正常运行。不确定您是否仍然愿意接受解决方案。尽管如此,这是你可以用Dictionary
原样做的事情。
虽然.NET的XmlSerializer
不支持字典,但有些库可以为您完成。一个这样的lib是SharpSerializer(Source,NuGet),它将任何类型序列化为二进制或XML。
用法非常简单:
var serializer = new SharpSerializer();
serializer.Serialize(dict, "test.xml");
<强>输入强>
var dict = new Dictionary<string, string[]>
{
{ "nikhil", new string[] { "nikhil.0@so.com", "nikhil.1@so.com" } }
};
<强>输出强>
<Dictionary name="Root" type="System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<Items>
<Item>
<Simple value="nikhil" />
<SingleArray>
<Items>
<Simple value="nikhil.0@so.com" />
<Simple value="nikhil.1@so.com" />
</Items>
</SingleArray>
</Item>
</Items>
</Dictionary>
答案 1 :(得分:0)
经过几天的努力,我得出的结论是,我使用的Serializable<TKey, TValue>
实现无法用于处理数组和其他对象。
我求助于在我的类上实现IXmlSerializable
接口,将字典值序列化为WriteXml
方法中的列表。在ReadXml
中,我只是反序列化存储的列表,并将其值重新放回字典中,同时检查没有重复的键存储为列表项的附加属性。它很笨重,但它确实有效。