Как десериализовать XML-файл в класс со свойством только для чтения?

У меня есть класс, который я использую как класс настроек, сериализованный в 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; }
    }
}

person Lloyd Cotten    schedule 25.09.2008    source источник
comment
Фактически вы не возвращаете коллекцию только для чтения из своего свойства SubSettings, вы возвращаете коллекцию, которую можно изменить.   -  person Matt Howells    schedule 25.09.2008
comment
Я не понимаю .. Что у тебя было раньше? Я имею в виду, что это просто мешает людям использовать SubSettings = Blah; Сама по себе коллекция не предназначена только для чтения?   -  person Rob Cooper    schedule 25.09.2008
comment
@ Роб Купер: в его коде коллекция НЕ предназначена только для чтения. Он по-прежнему возвращает изменяемую коллекцию, он просто не может изменить ссылку, используемую классом. Если это то, что он намеревался, это нормально.   -  person user7116    schedule 25.09.2008
comment
@ Роб Купер: да, извините, я имел в виду, что само свойство Collection доступно только для чтения, и я не хочу, чтобы потребители моего класса повторно создавали или изменяли его, кроме добавления к нему содержимого. Извините, исходный вопрос не ясен.   -  person Lloyd Cotten    schedule 25.09.2008
comment
Потрясающе, я столкнулся с той же проблемой. Спасибо за обновление с решением!   -  person TWith2Sugars    schedule 15.01.2009


Ответы (4)


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

person leppie    schedule 25.09.2008
comment
Да, спасибо, на самом деле это IEnumerable или ICollection, но да, ваш ответ очень близок к тому, что я обнаружил. - person Lloyd Cotten; 25.09.2008

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

person Quintin Robinson    schedule 25.09.2008

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

Я хотел бы реализовать ISerializable и сделайте это вручную. Отсюда вы сможете установить внутренние значения.

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

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

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

Это не? Если нет, можете ли вы вставить код, чтобы я мог видеть, что именно вы делаете? Есть несколько способов сделать все это :)

person Rob Cooper    schedule 25.09.2008
comment
Да, спасибо за ответ ... Я надеялся, что мне не придется делать это вручную. Оказывается, в данном случае я этого не делал (см. Отредактировать вопрос). Если бы это было более сложно, мне, вероятно, пришлось бы пойти по этому пути. - person Lloyd Cotten; 25.09.2008
comment
Приносим извинения за задержку в редактировании, сайт был закрыт перед отправкой! : D - person Rob Cooper; 25.09.2008

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

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

person Lloyd Cotten    schedule 25.09.2008