我一直在阅读的各个地方都指出,在反序列化时,.NET Framework会调用FormatterServices.GetUninitializedObject,其中不调用构造函数,也不设置字段初始值设定项。如果这是真的,为什么我的构造函数被调用?是否存在构造函数和字段初始值设定项可以被调用的实例?
我的班级:
[DataContract]
public class TestClass
{
[DataMember]
public string Val1 { get; set; }
[DataMember]
public string Val2 { get; set; }
[DataMember]
public bool NonDefaultBool = true;
private int _nonDefaultInt = 1234;
[DataMember]
public int NonDefaultInt
{
get { return _nonDefaultInt; }
set { _nonDefaultInt = value; }
}
public TestClass()
{
Val1 = "hello";
}
}
我的de /序列化代码:
var json2 =
@"{
""Val1"":""hello""
}";
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json2)))
{
var thing = DeserializeJsonObject<TestClass>(ms);
Console.WriteLine(GetSerializedData(thing));
}
// ... code left out
protected static TModel DeserializeJsonObject<TModel>(Stream data) where TModel : class
{
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(TModel));
return jsonSerializer.ReadObject(data) as TModel;
}
static string GetSerializedData<T>(T data)
{
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(T), _knownTypes);
using (MemoryStream ms = new MemoryStream())
{
jsonSerializer.WriteObject(ms, data);
return Encoding.UTF8.GetString(ms.ToArray());
}
}
我的输出(格式化并评论我):
{
"NonDefaultBool":false, // field initializer not set
"NonDefaultInt":0, // field initializer not set
"Val1":"hello", // constructor called
"Val2":null
}
答案 0 :(得分:3)
您正在反序列化json2字符串。
var json2 =
@"{
""Val1"":""hello""
}";
我不相信构造函数被调用,但'hello'是由JSON字符串赋值的。
答案 1 :(得分:3)
如果它可能对其他人有用。答案是在数据协定上提供[OnDeserializing]处理程序。在您的情况下,实现将如下所示:
[DataContract]
public class TestClass
{
[DataMember]
public string Val1 { get; set; }
[DataMember]
public string Val2 { get; set; }
[DataMember]
public bool NonDefaultBool;
[DataMember]
public int NonDefaultInt { get; set; }
private void InitializeDefaults()
{
Val1 = "hello";
NonDefaultBool = true;
NonDefaultInt = 1234;
}
#region Construction
public TestClass()
{
InitializeDefaults();
}
[OnDeserializing]
private void OnDeserializing(StreamingContext context)
{
InitializeDefaults();
}
#endregion
}
答案 2 :(得分:1)
好的,所以在再次抱怨之后,如果你愿意继承一个基类,并且不太担心使用Reflection,我会想出一个解决方案:
[DataContract]
class ConstructedDataContract
{
[OnDeserializing]
void OnDeserializing(StreamingContext context)
{
ConstructorInfo ci = this.GetType().GetConstructor(new Type[] { });
if (ci != null)
{
ci.Invoke(this, new object[] { });
}
}
}
然后继承该基类
[DataContract]
class MyClass1 : ConstructedDataContract
{
[DataMember(IsRequired=false)]
public int Var1 = 5; // This will initialise to 5, and if the field is
// included in the serialisation stream, then it
// will be overwritten.
}
将在基类上调用OnDeserializing,它将使用反射来运行类的默认构造函数。在上面的例子中,默认构造函数将Var1设置为5,即使没有显式的构造函数块。如果有,那么该块的代码也将被执行。