使用DataContractSerializer时,是否可以初始化只读字段?

时间:2012-02-23 19:55:16

标签: c# initialization datacontractserializer

反序列化时,

DataContractSerializer不调用构造函数或调用字段初始值设定项:

DataContractSerializer doesn't call my constructor?

Field Initializer in C# Class not Run when Deserializing

Setting the initial value of a property when using DataContractSerializer

是否可以在对象反序列化后初始化readonly字段?我必须放弃该语言功能才能使用DataContractSerializer吗?

3 个答案:

答案 0 :(得分:3)

我不确定这样做是个好主意,但您可以使用反射更改构造函数或字段初始值设定项外的readonly字段的值。

如下所示:

typeof(MyType).GetField("Field").SetValue(this, value);
你的反序列化回调中的

应该可以工作。

答案 1 :(得分:2)

是的,使用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;
        }
    }
}

答案 2 :(得分:0)

我找到了一种干净的方法,可以在不破坏设计的情况下实现您的目标。

使用此方法将确保将调用构造函数并正确设置readonly字段。


您需要的是从DataModel类中实际序列化和反序列化[DataMember]个标记的字段。

这将防止任何意外的行为发生,因为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);
}

当然,你必须为构造函数添加一个重载,你可能需要稍微调整一下这个例子,但我想你已经了解了。