Constructors Not Called On Deserialization

爱⌒轻易说出口 提交于 2019-12-24 05:35:30

问题


Various places I've been reading have pointed out that on deserialization, the .NET Framework makes a call to FormatterServices.GetUninitializedObject, in which constructors are not called and field initializers are not set. If this is true, why is my constructor being called? Are there instances where constructors and field initializers could be called?

My Class:

[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";
    }
}

My de/serialization code:

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());
    }
}

My output (formatted and commented me):

{
    "NonDefaultBool":false, // field initializer not set
    "NonDefaultInt":0, // field initializer not set
    "Val1":"hello", // constructor called
    "Val2":null
}

回答1:


You're deserializing the json2 string.

var json2 =
@"{
""Val1"":""hello""
}";

I don't believe the constructor is being called, but the 'hello' is being assigned by the JSON string.




回答2:


In case it might be useful for someone else. The answer is providing [OnDeserializing] handler on your data contract. In your case the implementation would look like:

[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
}



回答3:


OK, so after complaining about it again, I've sort-of come up with a solution, if you're willing to inherit a base class, and not too bothered about using Reflection:

[DataContract]
class ConstructedDataContract
{
    [OnDeserializing]
    void OnDeserializing(StreamingContext context)
    {
        ConstructorInfo ci = this.GetType().GetConstructor(new Type[] { });
        if (ci != null)
        {
            ci.Invoke(this, new object[] { });
        }
    }
}

Then just inherit that base class

[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 will be called on the base class, which will use reflection to run the classes default constructor. In the case above, the default constructor sets Var1 to 5, even though there is no explicit constructor block. If there were, then code from that block would be executed too.



来源:https://stackoverflow.com/questions/5021973/constructors-not-called-on-deserialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!