我正在尝试反序列化包含从通用接口派生的子项的类。这是我的界面和两个示例类:
public interface IItem<T> : IXmlSerializable
{
T Value { get; set; }
string Name { get; set; }
List<IItem<T>> ChildItems { get; set; }
}
public class TypeA : IItem<string>
{
public string Value { get; set; }
public string Name { get; set; }
public List<IItem<string>> ChildItems { get; set; }
public TypeA()
{
ChildItems = new List<IItem<string>>();
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
var userQuery = new UserQuery();
Func<string, string> converter = value => value;
userQuery.ReadFromXml(reader, this, converter);
}
public void WriteXml(XmlWriter writer)
{
var userQuery = new UserQuery();
userQuery.WriteToXml(this, writer);
}
}
public class TypeB : IItem<int>
{
public int Value { get; set; }
public string Name { get; set; }
public List<IItem<int>> ChildItems { get; set; }
public TypeB()
{
ChildItems = new List<IItem<int>>();
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
var userQuery = new UserQuery();
Func<string, int> converter = value => Convert.ToInt16(value);
userQuery.ReadFromXml<int>(reader, this, converter);
}
public void WriteXml(XmlWriter writer)
{
var userQuery = new UserQuery();
userQuery.WriteToXml(this, writer);
}
}
我读了很多SO文章,得出结论,我需要使用IXmlSerializable接口实现自己的序列化。到目前为止,序列化效果很好!这是我用来序列化的方法:
public void WriteToXml<T>(IItem<T> item, XmlWriter writer)
{
writer.WriteElementString("Value", item.Value.ToString());
writer.WriteElementString("Name", item.Name);
writer.WriteStartElement("ChildItems");
foreach (var child in item.ChildItems)
{
// i want the name of the type to be the element name
writer.WriteStartElement(child.GetType().Name);
child.WriteXml(writer);
writer.WriteEndElement();
}
writer.WriteEndElement();
}
我的问题是反序列化子项。我对孩子进行反序列化的方法如下:
public void ReadFromXml<T>(XmlReader reader, IItem<T> item, Func<string, T> parseExpectedValue)
{
reader.MoveToContent();
reader.ReadToFollowing("Value");
item.Value = parseExpectedValue(reader.ReadElementString("Value"));
reader.ReadToFollowing("Name");
item.Name = reader.ReadElementString("Name");
// todo: how to implement reading of child items ??
reader.ReadToFollowing("ChildItems");
// the statement below throws an InvalidOperationException with
// the inner exception message: Unexpected node type Element. ReadElementString method can only be called on elements with simple or empty content
var value = reader.ReadElementString();
}
对于序列化和反序列化,我使用以下方法:
public string Serialize<T>(T item)
{
var type = item.GetType();
var serializer = new XmlSerializer(type);
var serializedItem = string.Empty;
using (var stringWriter = new StringWriter())
{
serializer.Serialize(stringWriter, item);
serializedItem = stringWriter.ToString();
}
return serializedItem;
}
public T Deserialize<T>(string serializedItem) where T : class
{
T item = null;
try
{
var type = typeof(T);
var serializer = new XmlSerializer(type);
using (var stringReader = new StringReader(serializedItem))
{
item = (T)serializer.Deserialize(stringReader);
}
}
catch (System.Exception ex)
{
ex.Dump();
}
return item;
}
当我序列化以下对象时,XML结果如下:
var testItemA = new TypeA()
{
Name = "TestTypeA",
Value = "TestValue",
ChildItems = new List<UserQuery.IItem<string>>()
{
new TypeA() { Name = "Str Child 1", Value = "Str Child Value 1", },
new TypeA() { Name = "Str Child 2", Value = "Str Child Value 2", ChildItems = new List<UserQuery.IItem<string>>(){ new TypeA(){ Name = "Str Child 3", Value = "Test Value 3" } }},
}
};
var testItemB = new TypeB()
{
Name = "TestTypeB",
Value = 1234,
ChildItems = new List<UserQuery.IItem<int>>()
{
new TypeB() { Name = "Child1", Value = 100, },
new TypeB() { Name = "Child2", Value = 200, }
}
};
XML输出:
<?xml version="1.0" encoding="utf-16"?>
<TypeA>
<Value>TestValue</Value>
<Name>TestTypeA</Name>
<ChildItems>
<TypeA>
<Value>Str Child Value 1</Value>
<Name>Str Child 1</Name>
<ChildItems />
</TypeA>
<TypeA>
<Value>Str Child Value 2</Value>
<Name>Str Child 2</Name>
<ChildItems>
<TypeA>
<Value>Test Value 3</Value>
<Name>Str Child 3</Name>
<ChildItems />
</TypeA>
</ChildItems>
</TypeA>
</ChildItems>
</TypeA>
<?xml version="1.0" encoding="utf-16"?>
<TypeB>
<Value>1234</Value>
<Name>TestTypeB</Name>
<ChildItems>
<TypeB>
<Value>100</Value>
<Name>Child1</Name>
<ChildItems />
</TypeB>
<TypeB>
<Value>200</Value>
<Name>Child2</Name>
<ChildItems />
</TypeB>
</ChildItems>
</TypeB>
我知道我必须遍历XML中的子元素,但是我必须使用XmlReader的哪些方法?