我想在稍微不同的场景中实现Craig Andera's custom XML configuration handler。我想要做的是读入定义为:
的任意长度的自定义对象列表public class TextFileInfo
{
public string Name { get; set; }
public string TextFilePath { get; set; }
public string XmlFilePath { get; set; }
}
我设法为一个自定义对象复制了Craig的解决方案但是如果我想要几个呢?
Craig的反序列化代码是:
public class XmlSerializerSectionHandler : IConfigurationSectionHandler
{
public object Create(object parent, object configContext, XmlNode section)
{
XPathNavigator nav = section.CreateNavigator();
string typename = (string)nav.Evaluate("string(@type)");
Type t = Type.GetType(typename);
XmlSerializer ser = new XmlSerializer(t);
return ser.Deserialize(new XmlNodeReader(section));
}
}
我想我能做到这一点,如果我能得到
Type t = Type.GetType("System.Collections.Generic.List<TextFileInfo>")
工作,但它抛出
Could not load type 'System.Collections.Generic.List<Test1.TextFileInfo>' from assembly 'Test1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
答案 0 :(得分:5)
我不认为这会在那种情况下起作用。 Craig的解决方案适用于简单的对象图,但集合有点棘手。列表被序列化为数组,因此将示例放入序列化列表中就像:
<ArrayOfTextFileInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlsns:xsd="http://www.w3.org/2001/XMLSchema>
<TextFileInfo>
<Name>My Text File</Name>
<TextFilePath>C:\MyTextFile.txt</TextFilePath>
<XmlFilePath>C:\MyXmlFile.xml</XmlFilePath>
</TextFileInfo>
</ArrayOfTextFileInfo>
现在,我猜你可以把它放在配置中,只要配置部分命名为“ArrayOfTextFileInfo”。不完全那么友好。我认为您应该做的是使用标准配置类来构建它:
public class TextFileConfigurationElement : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true, IsKey = true)]
public string Name {
get { return (string)this["name"]; }
set { this["name"] = value; }
}
[ConfigurationProperty("textFilePath")]
public string TextFilePath {
get { return (string)this["textFilePath"]; }
set { this["textFilePath"] = value; }
}
[ConfigurationProperty("xmlFilePath")]
public string XmlFilePath {
get { return (string)this["xmlFilePath"]; }
set { this["xmlFilePath"] = value; }
}
}
[ConfigurationCollection(typeof(TextFileConfigurationElement))]
public class TextFileConfigurationElementCollection : ConfigurationElementCollection
{
protected override void CreateNewElement() {
return new TextFileConfigurationElement();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((TextFileConfigurationElement)element).Name;
}
}
public class TextFilesConfigurationSection : ConfigurationSection
{
[ConfigurationProperty("files")]
public TextFileConfigurationElementCollection Files {
get { return (TextFileConfigurationElementCollection)this["files"]; }
set { this["files"] = value; }
}
public static TextFilesConfigurationSection GetInstance() {
return ConfigurationManager.GetSection("textFiles") as TextFilesConfigurationSection;
}
}
注册配置部分后:
<configSections>
<add name="textFiles" type="...{type here}..." />
</configSections>
您可以添加配置:
<textFiles>
<files>
<add name="File01" textFilePath="C:\File01.txt" xmlTextFile="C:\File01.xml" />
</files>
</textFiles>
在代码中使用它:
public List<TextFileInfo> GetFiles() {
var list = new List<TextFileInfo>();
var config = TextFileConfigurationSection.GetInstance();
if (config == null)
return list;
foreach (TextFileConfigurationElement fileConfig in config.Files) {
list.Add(new TextFileInfo
{
Name = fileConfig.Name,
TextFilePath = fileConfig.TextFilePath,
XmlFilePath = fileConfig.XmlFilePath
});
}
return list;
}
另外,这个:
Type t = Type.GetType("System.Collections.Generic.List<TextFileInfo>")
由于几个原因无法工作,你还没有完全限定TextFileInfo类型(需要命名空间),并且你对泛型类型的定义是错误的(我可以看到为什么你没有这样指定它),它应该看起来像:
Type t = Type.GetType("System.Collections.Generic.List`1[MyNamespace.TextFileInfo]");
希望有所帮助!