簡體   English   中英

如何動態添加XmlInclude屬性

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM