How does WCF deserialization instantiate objects without calling a constructor?

19,914

Solution 1

FormatterServices.GetUninitializedObject() will create an instance without calling a constructor. I found this class by using Reflector and digging through some of the core .Net serialization classes.

I tested it using the sample code below and it looks like it works great:

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

Solution 2

Yes, FormatterServices.GetUninitializedObject() is the source of the magic.

If you want to do any special initialization, see this. http://blogs.msdn.com/drnick/archive/2007/11/19/serialization-and-types.aspx

Share:
19,914

Related videos on Youtube

Drew Noakes
Author by

Drew Noakes

Developer on .NET at Microsoft.

Updated on February 11, 2020

Comments

  • Drew Noakes
    Drew Noakes about 4 years

    There is some magic going on with WCF deserialization. How does it instantiate an instance of the data contract type without calling its constructor?

    For example, consider this data contract:

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

    When obtaining an instance of this object via DataContractSerializer you will see that the field _wasConstructorCalled is false.

    So, how does WCF do this? Is this a technique that others can use too, or is it hidden away from us?

  • Jason Jackson
    Jason Jackson over 15 years
    Well, I previously posted a wrong answer (now deleted) so I felt guilty. Nothing like bruising a programmers ego to get him to do some research.
  • harpo
    harpo almost 14 years
    Is anyone else now wondering, how does FormatterServices.GetUninitializedObject work, then? Reflection?
  • Jason Jackson
    Jason Jackson almost 14 years
    If I recall its a call into native code. I couldn't follow this any farther down the rabbit hole with Reflector.
  • bushed
    bushed over 12 years
    Weird - I run that code in linqpad and I got: 0 0 as output. Actually that makes sense to me since field initializers are inlined into ctors AFAIK
  • Oliver
    Oliver over 11 years
    @bushed is correct. I've posted a screenshot with the code and result here. At first I thought it might be a difference in the .NET framework versions (since the answer is already 4 years old) but I checked for 2.0 and 4.0 and they both write 0 and 0 to the console. Jason Jackson, Could you update your post to reflect these findings?
  • bas
    bas over 9 years
    +1 for the reference, [OnDeserialized] was the solution for me!