Как десериализовать производный класс с другим производным классом как свойством - PullRequest
1 голос
/ 20 сентября 2019

У меня 2 проекта.Одно из них - приложение WPF, а второе - мой «инструментарий» с предопределенным управлением WPF, десериализацией XML и некоторыми базовыми классами конфигурации.

В моем наборе инструментов есть класс ConfigurationBase:

public class ConfigurationBase : XmlDeserializeConfigSectionHandler
{
      public GuiConfigurationBase GuiConfiguration { get; set; }
}

Это GuiConfigurationBase

public class GuiConfigurationBase
{
    public int LogLineCount { get; set; }
}

Мой инструментарий содержит предопределенный просмотр сообщений в журнале приложения.Поэтому моему конструктору LogViewModel требуется ConfigurationBase, который должен содержать GuiConfiguration со свойством LogLineCount.

Это потому, что я не хочу внедрять в журнал приложений каждое приложение.

Тогда у меня есть проект WPF.Он содержит класс Config, производный от ConfigurationBase.Это расширено с некоторыми другими опорами, которые не важны.

Мне также нужно было расширить GuiConfigurationBase, поэтому у меня есть класс с именем GuiConfiguration, который происходит от GuiConfigurationBase.

public class Config : ConfigurationBase
{
    public string AppName { get; set; }
}

public class GuiConfiguration : GuiConfigurationBase
{
    public int TextSize { get; set; }
}

IЯ также использую XmlSerializer для десериализации моего XML-файла.Мне нужно заполнить оба моих производных класса.

Как мне этого добиться, пожалуйста?

Я попробовал некоторую абстракцию для базовых классов, но безуспешно.

Спасибо за любые предложения.

1 Ответ

0 голосов
/ 24 сентября 2019

Я нашел решение.Необходимо использовать XmlAttributeOverrides.

Поскольку у меня есть два проекта, мне пришлось использовать рефлексию для извлечения классов, производных от GuiConfigurationBase.(Я ничего не знаю о проекте, на который ссылается мой проект инструментария)

Затем добавьте новый XmlElementAttribute для каждого класса (в моем случае должно быть достаточно использовать метод Linq First()) - Это должнобыть таким же как XmlIncludeAttribute (Тип)

И, наконец, добавить XmlAttributeOverrides для ConfigurationBase свойства класса GuiConfiguration

Вот мой метод десериализации:

 public T Deserialize<T>(string input) where T : class
    {
        //Init attrbibutee overrides
        XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
        XmlAttributes attrs = new XmlAttributes();

        //Load all types which derive from GuiConfiguration base
        var guiConfTypes = (from lAssembly in AppDomain.CurrentDomain.GetAssemblies()
                            from lType in lAssembly.GetTypes()
                            where typeof(GuiConfigurationBase).IsAssignableFrom(lType) && lType != typeof(GuiConfigurationBase)
                            select lType).ToArray();


        //All classes which derive from GuiConfigurationBase
        foreach (var guiConf in guiConfTypes)
        {
            XmlElementAttribute attr = new XmlElementAttribute
            {
                ElementName = guiConf.Name,
                Type = guiConf
            };

            attrs.XmlElements.Add(attr);
        }

        //Add Attribute overrides for ConfigurationBase class's property GuiConfiguration
        attrOverrides.Add(typeof(ConfigurationBase), nameof(ConfigurationBase.GuiConfiguration), attrs);

        XmlSerializer ser = new XmlSerializer(typeof(T), attrOverrides);

        using (StringReader sr = new StringReader(input))
        {
            return (T)ser.Deserialize(sr);
        }
    }

Надеюсь, это поможет кому-то еще: -)

...