Конструкторы, не вызываемые при десериализации - PullRequest
2 голосов
/ 16 февраля 2011

В различных местах, которые я читал, указывалось, что при десериализации .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";
    }
}

Мой код де / сериализации:

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
}

Ответы [ 3 ]

3 голосов
/ 10 ноября 2014

В случае, если это может быть полезно для кого-то еще.Ответом является предоставление обработчика [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
}
3 голосов
/ 17 февраля 2011

Вы десериализуете строку json2.

var json2 =<br> @"{<br> ""Val1"":""hello""<br> }";

Я не верю, что конструктор вызывается, но 'привет' присваивается строкой JSON.

1 голос
/ 24 июня 2016

ОК, поэтому после повторных жалоб я как-то нашел решение, если вы хотите наследовать базовый класс и не слишком беспокоитесь об использовании 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, хотя явного блока конструктора не существует. Если бы это было так, то код из этого блока тоже был бы выполнен.

...