¿Cómo la deserialización de WCF crea instancias de objetos sin llamar a un constructor?

79

Hay algo de magia con la deserialización de WCF. ¿Cómo crea una instancia del tipo de contrato de datos sin llamar a su constructor?

Por ejemplo, considere este contrato de datos:

[DataContract]
public sealed class CreateMe
{
   [DataMember] private readonly string _name;
   [DataMember] private readonly int _age;
   private readonly bool _wasConstructorCalled;

   public CreateMe()
   {
      _wasConstructorCalled = true;
   }

   // ... other members here
}

Al obtener una instancia de este objeto a través de DataContractSerializer, verá que el campo _wasConstructorCalledes false.

Entonces, ¿cómo hace esto WCF? ¿Es esta una técnica que otros pueden usar también, o está escondida de nosotros?

Dibujó Noakes
fuente

Respuestas:

102

FormatterServices.GetUninitializedObject()creará una instancia sin llamar a un constructor. Encontré esta clase usando Reflector y explorando algunas de las clases principales de serialización de .Net.

Lo probé usando el código de muestra a continuación y parece que funciona muy bien:

using System;
using System.Reflection;
using System.Runtime.Serialization;

namespace NoConstructorThingy
{
    class Program
    {
        static void Main()
        {
            // does not call ctor
            var myClass = (MyClass)FormatterServices.GetUninitializedObject(typeof(MyClass));

            Console.WriteLine(myClass.One); // writes "0", constructor not called
            Console.WriteLine(myClass.Two); // writes "0", field initializer not called
        }
    }

    public class MyClass
    {
        public MyClass()
        {
            Console.WriteLine("MyClass ctor called.");
            One = 1;
        }

        public int One { get; private set; }
        public readonly int Two = 2;
    }
}

http://d3j5vwomefv46c.cloudfront.net/photos/large/687556261.png

Jason Jackson
fuente
6
Bueno, anteriormente publiqué una respuesta incorrecta (ahora eliminada), así que me sentí culpable. No hay nada como herir el ego de un programador para que investigue un poco.
Jason Jackson
3
¿Alguien más se pregunta ahora cómo funciona FormatterServices.GetUninitializedObject, entonces? ¿Reflexión?
harpo
Si recuerdo, es una llamada al código nativo. No podría seguir esto más allá de la madriguera del conejo con Reflector.
Jason Jackson
6
Extraño: ejecuté ese código en linqpad y obtuve: 0 0 como salida. En realidad eso tiene sentido para mí ya inicializadores entre líneas de campo están en ctors yo sepa
bushed
1
@bushed es correcto. He publicado una captura de pantalla con el código y el resultado aquí . Al principio pensé que podría haber una diferencia en las versiones de .NET framework (ya que la respuesta ya tiene 4 años) pero verifiqué 2.0 y 4.0 y ambos escriben 0 y 0 en la consola. Jason Jackson, ¿podría actualizar su publicación para reflejar estos hallazgos?
Oliver