как читать в списке пользовательских объектов конфигурации - PullRequest
0 голосов
/ 06 июня 2010

Я хочу реализовать пользовательский обработчик XML-конфигурации Крейга Андеры в несколько ином сценарии. Что я хочу сделать, это прочитать список произвольной длины пользовательских объектов, определенных как:

public class TextFileInfo
{
    public string Name { get; set; }
    public string TextFilePath { get; set; }
    public string XmlFilePath { get; set; }
}

Мне удалось воспроизвести решение Крейга для одного пользовательского объекта, но что, если я хочу несколько?

Код десериализации Крейга:

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'.

1 Ответ

5 голосов
/ 07 июня 2010

Я не думаю, что это будет работать в этом сценарии. Решение Крейга хорошо работает для простых графов объектов, но коллекции немного сложнее. Списки сериализуются в виде массивов, поэтому, если поместить ваш пример, сериализованный список выглядит примерно так:

<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]");

Надеюсь, это поможет!

...