1

我正在制作一个程序,它将加载基于 xml 的配置文件(虽然不是 app.config)。

在这个配置文件中,我将指定必须由程序实例化和配置的类型。

这是我如何设想的一个例子:

<?xml version="1.0"?>
<configuration>
    <types>
        <type assembly="SomeAssembly.dll" class="SomeAssembly.SomeClass">
            <type-configuration>
               <address>192.168.0.1</address>
               <port>80</port>
            </type-configuration>
        </type>
    </types>
</configuration>

那个最里面的元素就是问题所在<type-configuration>。里面的元素将取决于 所需的特定配置SomeAssembly.SomeClass,并且根本不为程序“所知”。

通过添加新类型,该部分可能如下所示:

<type assembly="SomeAssembly.dll" class="SomeAssembly.SomeClass">
    <type-configuration>
       <address>192.168.0.1</address>
       <port>80</port>
    </type-configuration>
</type>
<type assembly="SomeOtherAssembly.dll" class="SomeOtherAssembly.SomeOtherClass">
    <type-configuration>
       <url>http://www.domain.com/path/to/webpage</url>
       <authentication-token>1234567890ABC</authentication-token>
    </type-configuration>
</type>

有什么方法可以将上述 XML 文件反序列化为强类型对象,并且仍然随身携带该子 XML 部分,以便类型本身可以将其反序列化为自己的对象?

IE。我的程序的配置类可能是这样的:

[XmlType("configuration")]
public class Configuration
{
    [XmlElement("types")]
    public Collection<SubType> Types
    {
        ...
    }
}

[XmlType("type")]
public class SubType
{
    [XmlElement("configuration")]
    public ??? Configuration { get; set; }
}

我如何声明该SubType.Configuration财产?这甚至可能吗?

请注意,最终,该属性中的任何数据都将提供给配置文件中指定类型的实例化对象。我还没有写那部分,所以不管怎样都行,真的,

这是一个完整的LINQPad程序,它演示了我想要什么,以及我已经走了多远:

void Main()
{
    const string xml = @"<?xml version=""1.0""?>
<configuration>
    <types>
        <type assembly=""SomeAssembly.dll"" class=""SomeAssembly.SomeClass"">
            <type-configuration>
            <address>192.168.0.1</address>
            <port>80</port>
            </type-configuration>
        </type>
        <type assembly=""SomeOtherAssembly.dll"" class=""SomeOtherAssembly.SomeOtherClass"">
            <type-configuration>
            <url>http://www.domain.com/path/to/webpage</url>
            <authentication-token>1234567890ABC</authentication-token>
            </type-configuration>
        </type>
    </types>
</configuration>";

    var serializer = new XmlSerializer(typeof(Configuration));
    using (var reader = new StringReader(xml))
    {
        var configuration = (Configuration)serializer.Deserialize(reader);
        configuration.Dump();
    }
}

[XmlType("configuration")]
public class Configuration
{
    private readonly Collection<SubType> _Types = new Collection<SubType>();

    [XmlArray("types")]
    public Collection<SubType> Types
    {
        get
        {
            return _Types;
        }
    }
}

[XmlType("type")]
public class SubType
{
    private readonly Collection<XmlNode> _Configuration = new Collection<XmlNode>();

    [XmlAttribute("assembly")]
    public string AssemblyName { get; set; }

    [XmlAttribute("class")]
    public string ClassName { get; set; }

    [XmlElement("type-configuration")]
    public Collection<XmlNode> Configuration
    {
        get
        {
            return _Configuration;
        }
    }
}

这将转储出两个SubType对象,但该Configuration属性仅包含该<type-configuration>...</type-configuration>部分的第一个子元素。将属性类型更改为string只给我最里面的文本,即。ip 地址或 url,并将其更改为XmlDocument与 for 相同XmlNode

4

1 回答 1

0

如何使用 Linq2Xml 解析您的 xml,而不是尝试使用 XmlSerializer 反序列化

var types = XDocument.Parse(xml)
                .Descendants("type")
                .Select(t => new SubType
                {
                    AssemblyName = t.Attribute("assembly").Value,
                    ClassName = t.Attribute("class").Value,
                    Configuration = t.Element("type-configuration")
                                     .Elements()
                                     .ToDictionary(c=>c.Name.LocalName,c=>c.Value)
                })
                .ToList();

public class SubType
{
    public string AssemblyName { get; set; }
    public string ClassName { get; set; }
    public Dictionary<string, string> Configuration { set; get; }
}
于 2013-08-31T15:25:25.927 回答