Wie instanziiert die WCF-Deserialisierung Objekte, ohne einen Konstruktor aufzurufen?

79

Bei der Deserialisierung von WCF ist etwas Magisches im Gange. Wie instanziiert es eine Instanz des Datenvertragstyps, ohne seinen Konstruktor aufzurufen?

Betrachten Sie beispielsweise diesen Datenvertrag:

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

Wenn Sie eine Instanz dieses Objekts über erhalten, sehen DataContractSerializerSie, dass das Feld _wasConstructorCalledist false.

Wie macht WCF das? Ist dies eine Technik, die auch andere anwenden können, oder ist sie uns verborgen?

Drew Noakes
quelle

Antworten:

102

FormatterServices.GetUninitializedObject()erstellt eine Instanz, ohne einen Konstruktor aufzurufen. Ich habe diese Klasse mithilfe von Reflector gefunden und einige der wichtigsten .Net-Serialisierungsklassen durchsucht.

Ich habe es mit dem folgenden Beispielcode getestet und es sieht so aus, als ob es großartig funktioniert:

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
quelle
6
Nun, ich habe zuvor eine falsche Antwort gepostet (jetzt gelöscht), also fühlte ich mich schuldig. Es gibt nichts Schöneres, als das Ego eines Programmierers zu verletzen, um ihn dazu zu bringen, Nachforschungen anzustellen.
Jason Jackson
3
Hat sich jetzt jemand gefragt, wie FormatterServices.GetUninitializedObject dann funktioniert? Betrachtung?
Harpo
Wenn ich mich erinnere, ist es ein Aufruf in nativen Code. Ich konnte das mit Reflector nicht weiter im Kaninchenbau verfolgen.
Jason Jackson
6
Seltsam - Ich führe diesen Code in Linqpad aus und habe: 0 0 als Ausgabe. Eigentlich , dass macht Sinn für mich , da Feld initializers in ctors AFAIK inlined sind
bushed
1
@bushed ist richtig. Ich habe einen Screenshot mit dem Code geschrieben und führen hier . Zuerst dachte ich, es könnte ein Unterschied in den .NET Framework-Versionen sein (da die Antwort bereits 4 Jahre alt ist), aber ich habe nach 2.0 und 4.0 gesucht und beide schreiben 0 und 0 in die Konsole. Jason Jackson, könnten Sie Ihren Beitrag aktualisieren, um diese Ergebnisse widerzuspiegeln?
Oliver