[英]How to add XmlInclude attribute dynamically
我有以下课程
[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
实例; 否则你会从动态编译中出血。
在马克的第一个答案大楼(我只需要读,所以我并不需要防止怪异输出),我使用了一个更加动态/通用型阵列占未知类型,受此启发CodeProject上 。
public static XmlSerializer GetSerializer()
{
var lListOfBs = (from lAssembly in AppDomain.CurrentDomain.GetAssemblies()
from lType in lAssembly.GetTypes()
where typeof(B).IsAssignableFrom(lType)
select lType).ToArray();
return new XmlSerializer(typeof(AList), lListOfBs);
}
(人们可能会提高它的效率,例如使用静态或只读类型数组而不是局部变量。这样可以避免重复使用Reflection。但是我不知道何时加载程序集以及类和属性初始化,知道是否会让你遇到麻烦。我的用法并不多,花时间去研究这一切,所以我只是多次使用相同的Reflection。)
看一下XmlSerializer的文档。 有一个构造函数需要将已知类型作为第二个参数。 这应该适用于你的用例。
我不认为属性可以在运行时应用,因为它们用于在CIL代码中创建元数据。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.