it-swarm.com.ru

Сериализация личных данных члена

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

public Guid Id { get; private set; }

Я пометил класс [Serializable] и реализовал интерфейс ISerializable.

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

public void SaveMyObject(MyObject obj)
{
    XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
    TextWriter tw = new StreamWriter(_location);
    serializer.Serialize(tw, obj);
    tw.Close();
}

К сожалению, он падает на первой строке с этим сообщением.

Исключительная ситуация InvalidOperationException: Невозможно создать временный класс (результат = 1) . Ошибка CS0200: Свойство или индексатор 'MyObject.Id' нельзя назначить - оно доступно только для чтения

Если я установлю свойство Id для public, оно будет работать нормально. Может кто-нибудь сказать мне, если я что-то делаю, или, по крайней мере, если это вообще возможно?

73
Jon Mitchell

Вы можете использовать DataContractSerializer (но учтите, что вы не можете использовать атрибуты XML - только элементы XML):

using System;
using System.Runtime.Serialization;
using System.Xml;
[DataContract]
class MyObject {
    public MyObject(Guid id) { this.id = id; }
    [DataMember(Name="Id")]
    private Guid id;
    public Guid Id { get {return id;}}
}
static class Program {
    static void Main() {
        var ser = new DataContractSerializer(typeof(MyObject));
        var obj = new MyObject(Guid.NewGuid());
        using(XmlWriter xw = XmlWriter.Create(Console.Out)) {
            ser.WriteObject(xw, obj);
        }
    }
}

Кроме того, вы можете реализовать IXmlSerializable и делать все самостоятельно - но это работает, по крайней мере, с XmlSerializer.

60
Marc Gravell

Вы можете использовать System.Runtime.Serialization.NetDataContractSerializer. Он более мощный и исправляет некоторые проблемы классического сериализатора Xml.

Обратите внимание, что для этого есть разные атрибуты.

[DataContract]
public class X
{
  [DataMember]
  public Guid Id { get; private set; }
}


NetDataContractSerializer serializer = new NetDataContractSerializer();
TextWriter tw = new StreamWriter(_location);
serializer.Serialize(tw, obj);

Правка:

Обновление на основе комментария Марка: вам, вероятно, следует использовать System.Runtime.Serialization.DataContractSerializer для вашего случая, чтобы получить чистый XML. Остальной код такой же.

6
Stefan Steinegger

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

Из MSDN:

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

Итак ... вам бы очень хотелось установить значение поля в конструкторе по умолчанию ... 

2
flalar

Это невозможно с этим конкретным режимом сериализации (см. Другие комментарии для обходных путей). Если вы действительно хотите оставить свой режим сериализации как есть, вы должны обойти ограничения фреймворка. Посмотрите это пример

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

0
jvenema