问题描述
我正在研究一个小项目,以学习如何在C#.NET中序列化对象.我创建了以下类,这是我尝试序列化的类:
I am working on a small project to learn how to serialize an object in C#.NET I created the following class that is the class I am attempting to serialize:
public class Object
{
private Dictionary<string, int> dictionaryStringInt;
public Object()
{
this.dictionaryStringInt = new Dictionary<string, int>();
}
public void AddToDictionary(string s, int i)
{
this.dictionaryStringInt.Add(s, i);
}
public List<DictionaryEntry> DictionaryStringInt
{
get
{
List<DictionaryEntry> list = new List<DictionaryEntry>();
foreach (KeyValuePair<string, int> element in dictionaryStringInt)
{
list.Add(new DictionaryEntry(element.Key, element.Value));
}
return list;
}
set
{
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (DictionaryEntry entry in value)
{
dictionary.Add(entry.Key, entry.Value);
}
dictionaryStringInt = dictionary;
}
}
public class DictionaryEntry
{
private string key;
private int value;
public DictionaryEntry()
{
this.key = string.Empty;
this.value = 0;
}
public DictionaryEntry(string key, int value)
{
this.key = key;
this.value = value;
}
[XmlAttribute("Key")]
public string Key
{
get
{
return key;
}
set
{
key = value;
}
}
[XmlText]
public int Value
{
get
{
return value;
}
set
{
this.value = value;
}
}
}
}
我在这里有完成此工作的代码:
And I have this code here that does the work:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.ClearTextBox();
SerialisationTest.Object @object = this.SetUpObject();
this.Serialize(@object);
@object = null;
@object = this.Deserialise(@"C:\Sources\SerialisationTest\test.xml");
this.textBox1.Text = @object.ToString();
this.DisplayXML(@object);
}
public void Serialize(SerialisationTest.Object @object)
{
XmlSerializer serializer = new XmlSerializer(typeof(SerialisationTest.Object));
using (TextWriter writer = new StreamWriter(@"C:\Sources\SerialisationTest\test.xml"))
{
serializer.Serialize(writer, @object);
}
}
public SerialisationTest.Object Deserialise(string path)
{
XmlSerializer serializer = new XmlSerializer(typeof(SerialisationTest.Object));
using (TextReader reader = new StreamReader(path))
{
return (SerialisationTest.Object)serializer.Deserialize(reader);
}
}
public void DisplayXML(SerialisationTest.Object @object)
{
XmlSerializer serializer = new XmlSerializer(typeof(SerialisationTest.Object));
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, @object);
this.textBox1.Text = writer.ToString();
}
}
public SerialisationTest.Object SetUpObject()
{
SerialisationTest.Object @object = new SerialisationTest.Object();
@object.AddToDictionary("1", 1);
@object.AddToDictionary("2", 2);
@object.AddToDictionary("3", 3);
return @object;
}
public void ClearTextBox()
{
this.textBox1.Text = "";
}
}
现在这是我在文本框中看到的结果:
Now here is the result I see in my textbox:
<?xml version="1.0" encoding="utf-16"?>
<Object xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DictionaryStringInt />
</Object>
现在,大多数代码只是我在尝试序列化事情.但是后来我尝试序列化DictionaryStringInt
,并在MSDN上看到Dictionary无法序列化.因此,我尝试通过使属性返回DictionaryEntry
列表并将该列表转换为setter中的字典来欺骗序列化程序.但是如您所见,DictionaryStringInt
的数据未序列化.我希望收到类似的东西:
Now most of the code is just me playing around trying to serialize things. But then I tried serializing the DictionaryStringInt
and saw on MSDN that Dictionary cannot be serialize. So I tried to cheat the serializer by having the property return a list of DictionaryEntry
and converting this list into a dictionary in the setter. But as you can see, the DictionaryStringInt
's data is not serialized. I was hoping to received something like:
<?xml version="1.0" encoding="utf-16"?>
<Object xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DictionaryStringInt>
<DictionaryEntry Key="1">1</DictionaryEntry>
<DictionaryEntry Key="2">2</DictionaryEntry>
<DictionaryEntry Key="3">3</DictionaryEntry>
</DictionaryStringInt>
</Object>
有人知道如何实现这一目标吗? (顺便说一句,我知道如果在反序列化字典时在XML中有多个相同的键,我会得到类似KeyAlreadyPresentException之类的东西,这是一种行为要求)
Does anyone know how to achieve this? (BTW I am aware that if I have multiple of the same key in the XML when deserializing the dictionary I'll get something like an KeyAlreadyPresentException of some sort and this is a behavior want)
谢谢!
修改
我刚刚发现"C:\Sources\SerialisationTest\test.xml"
包含正确的结果.
I just found out that the "C:\Sources\SerialisationTest\test.xml"
contains the right result.
因此使用StringWriter进行反序列化或显示序列化似乎存在问题.
So there seems to be a problem with the deserialisation or the displaying of the serialisation using the StringWriter.
我在做错什么吗?
Edit2
简化代码
Edit3
我看了评论中链接的答案,我想我知道发生了什么...在其中一个答案中,有一条评论指出将不调用setter,而应使用数组.我正在调查这个.
I looked at the answer linked in the comment and I think I got what is going on... In one of the answers there is a comment that point that the setter wont be called and that I should use an array instead. I'm looking into this.
推荐答案
问题是您在反序列化期间丢失了代理List<DictionaryEntry> DictionaryStringInt
属性的内容.解决方法是将其更改为数组:
The problem is that you are losing the contents of your surrogate List<DictionaryEntry> DictionaryStringInt
property during deserialization. The workaround is to change it to an array:
DictionaryEntry [] DictionaryStringInt
{
get
{
if (dictionaryStringInt == null)
return null;
List<DictionaryEntry> list = new List<DictionaryEntry>();
foreach (KeyValuePair<string, int> element in dictionaryStringInt)
{
list.Add(new DictionaryEntry(element.Key, element.Value));
}
return list.ToArray();
}
set
{
if (value == null)
return;
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (DictionaryEntry entry in value)
{
dictionary.Add(entry.Key, entry.Value);
}
dictionaryStringInt = dictionary;
}
}
有关为什么List<DictionaryEntry>
代理属性在反序列化期间失败的解释,请参见无法使用XML反序列化器将XML反序列化为列表一个>.如此处所述:
For an explanation of why a List<DictionaryEntry>
surrogate property fails during deserialization, see Cannot deserialize XML into a list using XML Deserializer. As explained there:
-
XmlSerializer
调用getter获取列表.如果为null,它将分配一个列表并通过setter进行设置.在读取列表时,它会在某些局部变量中保留列表.
XmlSerializer
calls the getter to get the list. If null, it allocates a list and sets it via the setter. It holds onto the list in some local variable while reading it.
它将反序列化每个列表元素,并将其添加到它持有的列表中.
It deserializes each list element, and adds it to the list it is holding.
就是这样.之后,它永远不会调用包含类的 list属性设置器.因此,列表的内容永远不会填充到您的字典中.
And that's it. It never calls the containing class's list property setter afterwards. Thus the contents of the list are never populated into your dictionary.
但是,由于数组一旦分配就无法调整大小,因此必须在读取和反序列化其内容后分配 并将其放回原处.因此,数组属性可以在反序列化期间充当代理.
But, since an array cannot be resized once allocated, it must be allocated and set back after its contents are read and deserialized. Thus, an array property can function as a surrogate during deserialization.
这篇关于C#无法让我的字典以XML序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!