Можно ли инициализировать поле только для чтения при использовании DataContractSerializer? - PullRequest
9 голосов
/ 23 февраля 2012

DataContractSerializer не вызывает конструктор и не вызывает инициализаторы поля при десериализации:

DataContractSerializer не вызывает мой конструктор?

Поле инициализатора вКласс C # не запускается при десериализации

Установка начального значения свойства при использовании DataContractSerializer

Можно ли инициализировать поле readonly после десериализации объекта?Должен ли я отказаться от этой языковой функции, чтобы использовать DataContractSerializer?

Ответы [ 3 ]

3 голосов
/ 24 февраля 2012

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

Положить что-то вроде:

typeof(MyType).GetField("Field").SetValue(this, value);

в вашем обратном вызове десериализации должен работать.

2 голосов
/ 24 февраля 2012

Да, используя DataContractSerializer, вы можете сериализовать поле readonly.Вы даже можете сериализовать поле, не являющееся public readonly.

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;

namespace ConsoleApplication30
{
    class Program
    {
        static void Main(string[] args)
        {
            Test a = new Test(1, 2);
            Test b;
            using (var ms = new MemoryStream())
            {
                DataContractSerializer ser = new DataContractSerializer(typeof(Test));
                ser.WriteObject(ms, a);
                ms.Position = 0;
                b = (Test) ser.ReadObject(ms);
            }
            Trace.Assert(a.Data1 == b.Data1);
            Trace.Assert(a.Data2 == b.Data2);
        }
    }

    [DataContract]
    public class Test
    {
        [DataMember]
        public readonly int Data1;

        [DataMember]
        private readonly int _data2;
        public int Data2
        {
            get { return _data2; }   
        }

        public Test(int data1, int data2)
        {
            Data1 = data1;
            _data2 = data2;
        }
    }
}
0 голосов
/ 12 декабря 2013

Я нашел чистый способ достичь того, что вы ищете, не нарушая ваш дизайн.

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


Что вам нужно, так это на самом деле сериализовать и десериализовать [DataMember] помеченные поля из класса DataModel.

Это предотвратит непреднамеренное поведение, зная, что DataContractSerializer не вызывает конструктор при десериализации.

namespace MyApp.DataModel
{
    //It is not mandatory to specify the DataContract since a default one will be
    //provided on recent version of .Net, however it is a good practice to do so.
    [DataContract(Name = "MyClassDataModel", Namespace = "MyApp.DataModel")]
    public class MyClassDataModel
    {
        [DataMember]
        public bool DataMemberExample{ get; set; }
    }

}

Для десериализации и сериализации теперь вы можете использовать этот класс для хранения ваших значений.

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

public MyObjectThatNeedToBeConstructed LoadData(){
    // ... 
    // get your reader (Stream) from the file system or wherever it's located
    var deserializer = new DataContractSerializer(typeof(MyClassDataModel));
    var storedModel = (MyClassDataModel)deserializer.ReadObject(reader);

    return new MyObjectThatNeedToBeConstructed(storedModel);
}

После сохранения вы можете извлечь необходимые данные из вашего класса, содержащие поле ReadOnly.

public void SaveData(MyObjectThatNeedToBeConstructed myObject){
    // ... 
    // get your writer (Stream) from memory or wherever it's located
    var serializer = new DataContractSerializer(typeof(MyClassDataModel));
    var dataModel = new MyClassDataModel{ DataMemberExample = myObject.DataMember};
    serializer.WriteObject(writer, dataModel);
}

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

...