如何 serialize/deserialize class-IList 集合的包装器?
How to serialize/deserialize class-wrapper of IList collection?
我有基础 class Control
,其中包含 属性 public ControlCollection Controls;
:
public abstract class Control {
...
public virtual string Name { get: set; }
public ControlCollection Controls;
public Control parent = null;
...
}
ControlCollection
是我自己的 class,它实现了 IList<Control>
:
public sealed class ControlCollection : IList<Control>, IMySerializable {
public int Count => _controls.Count;
public bool IsReadOnly { get; } = false;
public Control Parent;
private List<Control> _controls = new List<Control>();
public ControlCollection(Control parent) {
Parent = parent ?? throw new ArgumentNullException("parent");
}
public Control this[int index] {
get => _controls[index];
set => _controls[index] = value;
}
public void Add(Control child) {
child.parent = Parent;
_controls.Add(child);
}
...
}
如果我将 属性 Controls
的类型从 ControlCollection
更改为 List<Control>
,那么下面的代码将形成一个正确的 XML 文件
// temp data
Control rootObj = new Button(); rootObj.Name = "111";
Control obj2 = new Label(); obj2.Name = "222";
Control obj3 = new Button(); obj3.Name = "333";
rootObj.Controls.Add(obj2);
rootObj.Controls.Add(obj3);
List<Type> list = new List<Type>();
rootObj.Controls.ForEach(child => child.DoActionWithChildren(node => {
list.Add(node.GetType());
}));
list.Add(typeof(Button));
list = list.Distinct().ToList();
// trying to set xml attributes. 'Controls' property will be a root of collection
var attributes = new XmlAttributes();
list.ForEach(t => attributes.XmlArrayItems.Add(new XmlArrayItemAttribute(t)));
var attrOverride = new XmlAttributeOverrides();
attrOverride.Add(typeof(Control), "Controls", attributes);
// save data to file
using(StreamWriter sw = new StreamWriter("path/to/xml/file.xml", false, Encoding.UTF8)) {
XmlSerializer xs = new XmlSerializer(typeof(Control), attrOverride);
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
xs.Serialize(sw, rootObj, ns);
}
/* ---------------------- */
output:
<?xml version="1.0" encoding="utf-8"?>
<Control d1p1:type="Button" xmlns:d1p1="http://www.w3.org/2001/XMLSchema-instance">
<Controls>
<Control d1p1:type="Label">
<Controls />
<Name>22222</Name>
</Control>
<Control d1p1:type="Button">
<Controls />
<Name>32333</Name>
</Control>
</Controls>
<Name>1111</Name>
</Control>
但是如果属性Controls
的一个类型是ControlCollection
,那么XML就会被截断:
<?xml version="1.0" encoding="utf-8"?>
<Button>
<Controls>
<Control d3p1:type="Label" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">
<Controls />
我尝试更改类型:attrOverride.Add(typeof(ControlCollection), "Controls", attributes);
,但这不起作用。
我应该怎么做才能正确序列化 ControlCollection
?我应该知道什么才能在之后正确反序列化它?
嗯,我修好了。原来我有一个循环引用,因为我的基础 class 中有一个 属性 public Control parent = null;
。我写了一个属性 [XmlIgnore]
并且它有效,即使使用 attrOverride.Add(typeof(ControlCollection), "Controls", attributes);
之所以没有看到这个错误,是因为我原来的项目是Unity项目。 Unity 没有向我显示该错误。当我制作一个简单的 C# 控制台应用程序时 - 它向我显示了该错误。很悲伤,但是很真实。
我有基础 class Control
,其中包含 属性 public ControlCollection Controls;
:
public abstract class Control {
...
public virtual string Name { get: set; }
public ControlCollection Controls;
public Control parent = null;
...
}
ControlCollection
是我自己的 class,它实现了 IList<Control>
:
public sealed class ControlCollection : IList<Control>, IMySerializable {
public int Count => _controls.Count;
public bool IsReadOnly { get; } = false;
public Control Parent;
private List<Control> _controls = new List<Control>();
public ControlCollection(Control parent) {
Parent = parent ?? throw new ArgumentNullException("parent");
}
public Control this[int index] {
get => _controls[index];
set => _controls[index] = value;
}
public void Add(Control child) {
child.parent = Parent;
_controls.Add(child);
}
...
}
如果我将 属性 Controls
的类型从 ControlCollection
更改为 List<Control>
,那么下面的代码将形成一个正确的 XML 文件
// temp data
Control rootObj = new Button(); rootObj.Name = "111";
Control obj2 = new Label(); obj2.Name = "222";
Control obj3 = new Button(); obj3.Name = "333";
rootObj.Controls.Add(obj2);
rootObj.Controls.Add(obj3);
List<Type> list = new List<Type>();
rootObj.Controls.ForEach(child => child.DoActionWithChildren(node => {
list.Add(node.GetType());
}));
list.Add(typeof(Button));
list = list.Distinct().ToList();
// trying to set xml attributes. 'Controls' property will be a root of collection
var attributes = new XmlAttributes();
list.ForEach(t => attributes.XmlArrayItems.Add(new XmlArrayItemAttribute(t)));
var attrOverride = new XmlAttributeOverrides();
attrOverride.Add(typeof(Control), "Controls", attributes);
// save data to file
using(StreamWriter sw = new StreamWriter("path/to/xml/file.xml", false, Encoding.UTF8)) {
XmlSerializer xs = new XmlSerializer(typeof(Control), attrOverride);
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
xs.Serialize(sw, rootObj, ns);
}
/* ---------------------- */
output:
<?xml version="1.0" encoding="utf-8"?>
<Control d1p1:type="Button" xmlns:d1p1="http://www.w3.org/2001/XMLSchema-instance">
<Controls>
<Control d1p1:type="Label">
<Controls />
<Name>22222</Name>
</Control>
<Control d1p1:type="Button">
<Controls />
<Name>32333</Name>
</Control>
</Controls>
<Name>1111</Name>
</Control>
但是如果属性Controls
的一个类型是ControlCollection
,那么XML就会被截断:
<?xml version="1.0" encoding="utf-8"?>
<Button>
<Controls>
<Control d3p1:type="Label" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">
<Controls />
我尝试更改类型:attrOverride.Add(typeof(ControlCollection), "Controls", attributes);
,但这不起作用。
我应该怎么做才能正确序列化 ControlCollection
?我应该知道什么才能在之后正确反序列化它?
嗯,我修好了。原来我有一个循环引用,因为我的基础 class 中有一个 属性 public Control parent = null;
。我写了一个属性 [XmlIgnore]
并且它有效,即使使用 attrOverride.Add(typeof(ControlCollection), "Controls", attributes);
之所以没有看到这个错误,是因为我原来的项目是Unity项目。 Unity 没有向我显示该错误。当我制作一个简单的 C# 控制台应用程序时 - 它向我显示了该错误。很悲伤,但是很真实。