在C# 使用XML序列化对象(一)中描述了使用XML序列化对象的最简单的实现。
现在我们来看看稍微复杂一点的情况:
现有两个类:A和B,B是A的派生类,如下所示:
public class A { public int a { get; set; } } public class B : A { public int b { get; set; } }
如果使用C# 使用XML序列化对象(一)中的方法来直接序列化类B的实例,会抛下面的异常:
"不应是类型 B。使用 XmlInclude 或 SoapInclude 特性静态指定非已知的类型。"
解决办法一:
在类A上使用XmlInclude特性标记类B,如下所示:
[XmlInclude(typeof(B))] public class A { public int a { get; set; } } public class B : A { public int b { get; set; } }
再使用如下代码序列化类B的实例:
B objB = new B { a = 1, b = 2 }; string xml = XmlSerialize(objB); var obj = XmlDeserialize<B>(txt.Text);
输出的XML如下所示:
<?xml version="1.0" encoding="utf-16"?> <B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <a>1</a> <b>2</b> </B>
当然,你也可以通过基类来序列化派生类,如下:
A objA = new B { a = 1, b = 2 }; string xml = XmlSerialize(objA); var obj = XmlDeserialize<A>(txt.Text);
这种方式输出的XML如下所示:
<?xml version="1.0" encoding="utf-16"?> <A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="B"> <a>1</a> <b>2</b> </A>
我们可以看到这里输出的XML里的标签名称是基类的名称,但是在属性中使用xsi:type="B"指定了对象的类型是派生类B。
还有另外一种方式可以不用在基类A上使用XmlInclude特性标记派生类B,如下:
public class A { public int a { get; set; } } public class B : A { public int b { get; set; } } A objA = new B { a = 1, b = 2 }; string xml = null; XmlSerializer xs = new XmlSerializer(typeof(A), new Type[] { typeof(B) }); using (TextWriter tw = new StringWriter()) { xs.Serialize(tw, objA); xml = tw.ToString(); } object obj = null; using (TextReader tr = new StringReader(xml)) { obj = xs.Deserialize(tr); }