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吗?
答案 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);
}
当然,你必须为构造函数添加一个重载,你可能需要稍微调整一下这个例子,但我想你已经了解了。