C Pottinger Ответов: 1

Попытка добавить переопределения атрибутов XML для массива производных классов


Привет, ребята.

Мне действительно нужна помощь. То, что я пытаюсь сделать, - это создать XML-сериализатор, который может обрабатывать класс, имеющий несколько производных подтипов. Я уже знаю основы этого: я написал эта запись в блоге чтобы помочь мне вспомнить, как это делается.

Но теперь я ныряю немного глубже, и я застрял. Ниже приведен упрощенный пример XML, с которым я работаю:
<AssignmentDesk name="test desk"/>
  <Extraction>
    <Find>
		...other instructions...
    </Find>
    <Find>
		...other instructions...
    </Find>
	<Set>
		...other instructions...
	</Set>
  </Extraction>
</AssignmentDesk>

И классы для представления этого выглядят так:
[XmlRoot("AssignmentDesk")]
public class AssignmentDesk
{
    [XmlAttribute("name")]
    public string Name { get; set; }

    [XmlElement("Extraction")]
    public List<Extractor> Extractors { get; set; }

    public static XmlAttributeOverrides GetXmlOverrides()
    {
        var attrs = new XmlAttributes();
        foreach (Type type in
            Assembly.GetAssembly(typeof(Instruction)).GetTypes()
            .Where(myType => myType.IsClass && myType.IsSubclassOf(typeof(Instruction))))
        {
            var attr = new XmlArrayItemAttribute(type);
            attrs.XmlArrayItems.Add(attr);
        }

        var overrides = new XmlAttributeOverrides();
        overrides.Add(typeof(Extractor), "SubInstructions", attrs);

        return overrides;
    }
}

public class Instruction
{
    public List<Instruction> SubInstructions { get; set; }
}

public class Extractor : Instruction
{
}

public class Find : Instruction
{
}

public class Set : Instruction
{
}

Конечно, все эти классы имеют другие атрибуты и методы. Я раздел их здесь до самого минимума.

А теперь ... Инструкция класс предназначен для представления множества различных инструкций (каждая из которых представлена классами, производными от ИнструкцияТо есть я хочу иметь возможность создавать дополнительные инструкции (например, Найди, Набор, Поставь, Finangle, или что-то еще) и пусть они будут распознаны XML-сериализатором как просто больше Инструкцияs. Для этого я использую GetXmlOverrides() метод на основе AssignmentDesk класса искать все классы, производные от Инструкции и добавьте их в переопределения атрибутов XML для Подструктуры собственность. Затем я использую возвращенные переопределения с помощью XML-сериализатора
var serializer = new XmlSerializer(typeof(AssignementDesk), overrides, null, new XmlRootAttribute(root), null);

Вот тут-то я и столкнулся с проблемами. Неважно, что я стараюсь, когда я десериализации XML-формате я вам Экстракторы установить в список, содержащий один Экстрактор объект (это хорошо). Но это Экстрактор объекта Подструктуры Список iвсегда пусто.
Я попытался изменить переопределения.добавить()
overrides.Add(typeof(AssignementDesk), "Extractors", attrs);
overrides.Add(typeof(AssignementDesk), "Extraction", attrs);
overrides.Add(typeof(Instruction), "SubInstructions", attrs);
etc.

Я попытался изменить тип атрибута с XmlArrayItemAttribute к Атрибут XmlElementAttribute Честно говоря, я не могу вспомнить все комбинации, которые я пробовал. Но ни один из них не сработал.
Есть ли у кого-нибудь представление о том, что я делаю неправильно?

Примечание: Вы можете быть удивлены, почему я просто не жестко кодирую [XmlArrayItem] атрибуты прямо над Экстракторы собственность (как я сделал с Инструменты класс в моей записи в блоге). Причина в том, что я надеюсь разрешить дополнительные инструкции (то есть классы, производные от Инструкция) быть созданным вне этого класса. Я не хочу жестко кодировать каждую новую инструкцию в AssignmentDesk.

Да, это много, вероятно, ненужной работы, но это также учебное упражнение для меня: если я научусь делать это в своем собственном домашнем проекте, то, возможно, я смогу в какой-то момент, спустя долгое время после того, как уйду на пенсию, дать какому-нибудь бедному ничего не подозревающему будущему сопровождающему кода сильную мигрень в 2 часа ночи в субботу (похвальная цель, вы должны признать).

Что я уже пробовал:

Варианты изменения типов атрибутов и имен членов, используемых для создания ПЕРЕОПРЕДЕЛЕНИЙ XML.
Проверка примеров, приведенных Microsoft (ни один из которых, похоже, не совсем то, что я делаю).
Подумывал о том, чтобы разгромить свой компьютер и стать мужчиной-стриптизером (определенно не очень хорошая идея)

1 Ответов

Рейтинг:
11

Richard Deeming

Проблема, по-видимому, заключается в том, что у вас нет элемента обертки, поэтому атрибуты массива игнорируются.

Если бы вы это сделали:

<Extraction>
    <SubInstructions>
        <Find />
        <Set />
    </SubInstructions>
</Extraction>
тогда ваш код будет работать.

Без оберточного элемента это выглядит так, как будто вам нужно использовать XmlElement вместо:
public static XmlAttributeOverrides GetXmlOverrides()
{
    var attrs = new XmlAttributes();
    
    foreach (Type type in
        Assembly.GetAssembly(typeof(Instruction)).GetTypes()
        .Where(myType => myType.IsClass && myType.IsSubclassOf(typeof(Instruction))))
    {
        var attr = new XmlElementAttribute(type);
        attrs.XmlElements.Add(attr);
    }

    var overrides = new XmlAttributeOverrides();
    overrides.Add(typeof(Instruction), "SubInstructions", attrs);
    return overrides;
}
Затем код работает с вашим текущим XML.

NB: Вам также необходимо добавить переопределение к Instruction тип, так как именно там определяется атрибут, а не к Extractor тип. Если вы хотите, чтобы переопределения применялись только к свойству, определенному на Extractor класс, тебе придется это сделать virtual, добавлять [XmlIgnore] в Instruction класс, и переопределить его в Extractor класс.


Maciej Los

5ed!

C Pottinger

- Спасибо, Ричард.
Я добавил переопределение атрибута XmlElementAttribute к объекту overrides и применил переопределения к типу инструкции, как вы и предлагали, теперь код работает идеально.
И спасибо Вам за объяснение того, как применить переопределение только к классу Extractor. Я не делаю этого в данном случае, но хорошо знать, что это вариант.

Идеальный ответ.