Як десеріалізація WCF створює екземпляри об’єктів без виклику конструктора?


79

З десериалізацією WCF відбувається якась магія. Як він створює екземпляр екземпляра типу контракту даних, не викликаючи його конструктор?

Наприклад, розглянемо цей контракт даних:

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

Отримавши екземпляр цього об'єкта через DataContractSerializerви побачите, що поле _wasConstructorCalledє false.

Отже, як WCF це робить? Це техніка, якою можуть скористатись і інші, чи вона прихована від нас?

Відповіді:


102

FormatterServices.GetUninitializedObject()створить екземпляр без виклику конструктора. Я знайшов цей клас за допомогою Reflector і перекопавши деякі основні класи серіалізації .Net.

Я протестував його за допомогою зразка коду нижче, і, схоже, він чудово працює:

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


6
Ну, я раніше опублікував неправильну відповідь (тепер видалено), тому відчував себе винним. Ніщо інше, як синяки его програмістів, щоб змусити його зробити якесь дослідження.
Джейсон Джексон,

3
Хтось ще задається питанням, як тоді працює FormatterServices.GetUninitializedObject? Роздум?
harpo

Якщо я згадую його виклик у рідний код. Я не міг прослідкувати за цим далі по кролячій норі за допомогою Reflector.
Джейсон Джексон,

6
Дивно - я запускаю цей код у linqpad і отримав: 0 0 як вихід. На насправді це має сенс для мене , так як польові ініціалізатор вбудованих в ctors AFAIK
втулка

1
@bushed - це правильно. Я розмістив скріншот з кодом і привести сюди . Спочатку я думав, що це може бути різниця у версіях .NET framework (оскільки відповіді вже 4 роки), але я перевірив наявність 2.0 і 4.0, і вони обидва пишуть 0 та 0 на консоль. Джейсон Джексон, не могли б ви оновити свою публікацію, щоб відображати ці висновки?
Олівер

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.