我有以下课程
[XmlRoot] public class AList { public List<B> ListOfBs {get; set;} } public class B { public string BaseProperty {get; set;} } public class C : B { public string SomeProperty {get; set;} } public class Main { public static void Main(string[] args) { var aList = new AList(); aList.ListOfBs = new List<B>(); var c = new C { BaseProperty = "Base", SomeProperty = "Some" }; aList.ListOfBs.Add(c); var type = typeof (AList); var serializer = new XmlSerializer(type); TextWriter w = new StringWriter(); serializer.Serialize(w, aList); } }
现在,当我尝试运行代码时,我在最后一行收到InvalidOperationException,说
不应使用XmlTest.C类型。使用XmlInclude或SoapInclude属性可以指定静态未知的类型。
我知道在[XmlRoot]中添加[XmlInclude(typeof(C))]属性将解决此问题。但是我想动态地实现它。因为在我的项目中,加载之前不知道C类。C类正在作为插件加载,因此我无法在其中添加XmlInclude属性。
我也尝试过
TypeDescriptor.AddAttributes(typeof(AList), new[] { new XmlIncludeAttribute(c.GetType()) });
之前
var type = typeof (AList);
但没有用。它仍然给出相同的例外。
是否有人对实现它有任何想法?
两种选择;最简单的(但给出奇数的xml)是:
XmlSerializer ser = new XmlSerializer(typeof(AList), new Type[] {typeof(B), typeof(C)});
带有示例输出:
<AList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ListOfBs> <B /> <B xsi:type="C" /> </ListOfBs> </AList>
更为优雅的是:
XmlAttributeOverrides aor = new XmlAttributeOverrides(); XmlAttributes listAttribs = new XmlAttributes(); listAttribs.XmlElements.Add(new XmlElementAttribute("b", typeof(B))); listAttribs.XmlElements.Add(new XmlElementAttribute("c", typeof(C))); aor.Add(typeof(AList), "ListOfBs", listAttribs); XmlSerializer ser = new XmlSerializer(typeof(AList), aor);
<AList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <b /> <c /> </AList>
无论哪种情况,您都 必须 缓存并重新使用该ser实例。否则您将因动态编译而流失内存。
ser