一尘不染

如何动态添加XmlInclude属性

c#

我有以下课程

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

但没有用。它仍然给出相同的例外。

是否有人对实现它有任何想法?


阅读 847

收藏
2020-05-19

共1个答案

一尘不染

两种选择;最简单的(但给出奇数的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实例。否则您将因动态编译而流失内存。

2020-05-19