Как десериализовать XML-файл в класс со свойством только для чтения? - PullRequest
2 голосов
/ 25 сентября 2008

У меня есть класс, который я использую в качестве класса настроек, который сериализован в XML-файл, который администраторы могут затем редактировать для изменения настроек в приложении. (Настройки немного сложнее, чем позволяет App.config.)

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

Чтобы добавить еще несколько деталей: этот конкретный класс является коллекцией, и, согласно FxCop, класс XmlSerializer имеет специальную поддержку десериализации коллекций только для чтения, но я не смог найти больше информации о нем. Точные данные о правиле, которое это нарушает:

Свойства, возвращающие коллекции, должны быть доступны только для чтения, чтобы пользователи не могли полностью заменить резервное хранилище. Пользователи по-прежнему могут изменять содержимое коллекции, вызывая соответствующие методы в коллекции. Обратите внимание, что класс XmlSerializer имеет специальную поддержку для десериализации коллекций только для чтения. См. Обзор XmlSerializer для получения дополнительной информации.

Это именно то, что я хочу, но как это сделать?

Редактировать: Хорошо, я думаю, что схожу с ума здесь. В моем случае все, что мне нужно было сделать, это инициализировать объект Collection в конструкторе, а затем удалить установщик свойств. Тогда объект XmlSerializable фактически знает, как использовать свойства Add / AddRange и indexer в объекте Collection. Следующее действительно работает!

public class MySettings
{
    private Collection<MySubSettings> _subSettings;
    public MySettings()
    {
       _subSettings = new Collection<MySubSettings>();
    }

    public Collection<MySubSettings> SubSettings
    {
         get { return _subSettings; }
    }
}

Ответы [ 4 ]

4 голосов
/ 25 сентября 2008

Вы должны использовать изменяемый тип списка, например ArrayList (или IList IIRC).

1 голос
/ 25 сентября 2008

@ Роб Купер сделал все правильно, просто внедрите интерфейс ISerializable , и вы сможете иметь собственный контроль над тем, как ваш класс сериализует и десериализует и устанавливает поля вручную. Это немного больше работы, но она достигнет желаемой цели. Удачи.

1 голос
/ 25 сентября 2008

Не думаю, что вы можете использовать автоматическую сериализацию, поскольку свойство доступно только для чтения.

Мой план действий - реализовать интерфейс ISerializable и сделать это вручную. Вы сможете установить внутренние значения отсюда.

Однако, если ваши подобъекты (которые доступны только для чтения) могут позаботиться о сериализации сами, все должно просто работать ..

Я думаю, что правило FxCop о том, что у вас есть что-то вроде:

public List<MyObject> Collection
{
   get { return _collection; }
   set { _collection = value; }
}

Разве это не так? Если нет, можете ли вы вставить какой-нибудь код, чтобы я мог видеть, что именно вы делаете? Есть несколько способов сделать все вышеперечисленное:)

0 голосов
/ 25 сентября 2008

@ Ответ Леппи был на самом деле самым близким. Это актуальный текст в документации по XmlSerializer, и я могу подробнее узнать об этом выше:

XmlSerializer предоставляет особый режим для классов, которые реализуют IEnumerable или ICollection. Класс, реализующий IEnumerable, должен реализовывать открытый метод Add, который принимает один параметр. Параметр метода Add должен иметь тот же тип, который возвращается из свойства Current для значения, возвращаемого из GetEnumerator или одной из основ этого типа. Класс, который реализует ICollection (например, CollectionBase) в дополнение к IEnumerable, должен иметь открытое индексированное свойство Item (indexer в C #), которое принимает целое число, и оно должно иметь открытое свойство Count типа integer. Параметр метода Add должен быть того же типа, который возвращается из свойства Item или одной из основ этого типа. Для классов, реализующих ICollection, значения для сериализации извлекаются из индексированного свойства Item, а не путем вызова GetEnumerator.

...