如何动态添加XmlInclude属性

我有以下课程

[XmlRoot] public class AList { public List 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(); 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)}); 

使用示例输出:

       

更优雅的是:

 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); 

使用示例输出:

     

在任何一种情况下,您都必须缓存并重新使用ser实例; 否则你会从动态编译中出血。

基于Marc的第一个答案(我只需阅读,所以我不需要阻止奇怪的输出),我使用更动态/generics的类型数组来解释未知类型,受此代码项目的启发。

  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代码中创建元数据。