使用动态加载的程序集中的类型将XML文档反序列化为.NET对象

时间:2011-11-25 20:57:54

标签: .net xml

我正在开发一个项目,我在核心程序集中有一系列配置类,我想让用户能够通过创建XML文档来创建配置对象的实例。

为此,我正在考虑为基类创建xsd文件。

我的下一个问题是我有一些动态加载的程序集,而且在设计时并不知道。他们都实现了一套通用的接口。

最大的问题是如何创建一个从动态加载的程序集中实例化嵌套类型的对象图?

E.g。

<mycoreobject>
  <somethings>
  <ass1:plugintype1 att="aaa"/> //implementing ISomthing from dynamically loaded assembly
  </somethings>
</mycoreobject>

最终结果我想要一个带有ISomethings列表的核心mycoreobject对象,它实际上被实例化为各自程序集中的类型。

在XAML中,我们通过定义命名空间来做类似的事情,每个命名空间都引用一个特定的程序集。在我的示例中,ass1将是externals程序集的别名。

我写的越多,我就越假设我只需要分析XML内容并手动构建对象图?

欢迎任何提示,想法或解决方案。

蒂亚

萨姆

1 个答案:

答案 0 :(得分:1)

喜欢这样吗?

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
public class MyBase
{
}
public class ConcreteType : MyBase
{
    [XmlAttribute("att")]
    public string Value { get; set; }
}
[XmlRoot("mycoreobject")]
public class SomeRoot
{
    public List<MyBase> Items { get; set; }
}
static class Program
{
    static void Main()
    {
        XmlAttributeOverrides xao = new XmlAttributeOverrides();
        XmlAttributes extraTypes = new XmlAttributes();
        extraTypes.XmlArray = new XmlArrayAttribute("somethings");
        // assume loaded dynamically, along with name/namespace
        extraTypes.XmlArrayItems.Add(new XmlArrayItemAttribute("plugintype1",
            typeof(ConcreteType)) { Namespace = "my-plugin-namespace" });
        xao.Add(typeof(SomeRoot), "Items", extraTypes);

        // important: need to cache and re-use "ser", or will leak assemblies
        XmlSerializer ser = new XmlSerializer(typeof(SomeRoot), xao);

        //example 1: writing
        var obj = new SomeRoot { Items = new List<MyBase> { new ConcreteType { Value = "abc" } } };
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");
        ns.Add("ass1", "my-plugin-namespace");
        ser.Serialize(Console.Out, obj, ns);

        // example 2: reading
        string xml = @"<mycoreobject xmlns:ass1=""my-plugin-namespace"">
  <somethings>
  <ass1:plugintype1 att=""aaa""/>
  </somethings>
</mycoreobject>";

        obj = (SomeRoot)ser.Deserialize(new StringReader(xml));
        var foundIt = (ConcreteType)obj.Items.Single();
        Console.WriteLine();
        Console.WriteLine(foundIt.Value); // should be "aaa"       
    }
}