Po wykopaniu w źródłach Newtonsoft.Json mogę podać algorytm implementacji obiektu, który jest tam używany. I tak, konstruktor jest zawsze prawie zawsze wywoływany (*). Pytanie brzmi tylko "który?". Oto kolorowy wersja odpowiedzi:
TL; DR Przede wszystkim Newtonsoft.Json tworzy JsonContract
typu, który masz zamiar deserializowania. To jest klasa abstrakcyjna. I ma różne implementacje dla słowników, tablic, obiektów itp. W twoim przypadku zostanie utworzona JsonObjectContract
. Kontrakt zawiera różne metadane dotyczące typu zserializowanego. Najbardziej interesujące są dla nas:
IsInstantiable
- określa czy rozszeregować typ jest chwilowe (patrz niżej)
Properties
- to zbiór właściwości obiektu
DefaultCreator
- domyślna metoda tworzenia używane do tworzenia obiektowi Func<object>
DefaultCreatorNonPublic
- określa, czy domyślny konstruktor jest niepubliczny
OverrideCreator
- kreator inny niż domyślny, stosowany, gdy aplikacja ma być JsonConstructorAttribute
d konstruktora do obiektu
ParametrizedCreator
- twórca, który nazywa paramterized konstruktora, jest ona wykorzystywana, jeśli nie mamy ani domyślnych ani nadpisywania twórców
CreatorParameters
- zbiór właściwości, które są wykorzystywane do twórcy nadpisania lub parametryzowaną twórcy
MemberSerialization
- ta wartość określa sposób serializowania właściwości i pól. Domyślnie jest ustawiony na OptOut
- tj. Wszyscy publiczni członkowie są serializowane. Jeśli chcesz wykluczyć niektóre, powinieneś użyć atrybutu JsonIgnore
. Ale jest też opcja Fields
, która mówi, że wszystkie publiczne i prywatne pola powinny być serializowane. Istnieje kilka opcji włączenia tej opcji. Ale domyślnie jest wyłączony.
Niektóre z tych metadanych można pobrać, odzwierciedlając metadane typu. Na przykład. IsInstantiable
oblicza się, sprawdzając, czy typ deserializacji nie jest abstrakcyjny i nie jest interfejsem. Niektóre metadane są dodawane przez DefaultContractResolver
. W szczególności definiuje sposób konstruowania obiektu. W pseudo-kod:
if (contract.IsInstantiable)
{
if (type has default constructor or its a value type)
{
contract.DefaultCreator = get default (parameterless) constructor;
contract.DefaultCreatorNonPublic = check if default constructor public
}
if (we have constructor marked with JsonConstructorAttribute)
{
contract.OverrideCreator = constructor marked with attribute
contract.CreatorParameters = get properties which match constructor parameters
}
else if (contract.MemberSerialization == MemberSerialization.Fields)
{
// only if the upplication if fully trusted
contract.DefaultCreator = FormatterServices.GetUninitializedObject
}
else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic)
{
if (we have one public constructor with parameters)
{
contract.ParametrizedCreator = constructor with parameters;
contract.CreatorParameters = get properties which match ctor parameters
}
}
}
Więc, jak widać prioirty idzie do konstruktora oznaczony atrybutem JsonConstructorAttribute
. Otrzymasz również błąd, jeśli istnieje więcej niż jeden taki konstruktor.
(*) Dalej jest jedyny przypadek, gdy obiekt można utworzyć bez wywoływania konstruktora. Na przykład. jeśli oznaczysz klasę atrybutem [JsonObject(MemberSerialization = MemberSerialization.Fields)]
, aby serializować prywatne pola.
Następnie sprawdzamy, czy mamy domyślny konstruktor bez parametrów, który nie jest prywatny. Jeśli tak, to idziemy do innego konstruktora - takiego, który ma parametry i powinien być publiczny. Jeśli istnieje więcej niż jeden taki konstruktor, dostaniesz również błąd.
I ostatnia rzecz do zapamiętania - CraeatorParameters
. Newtonsoft.Json używa odbicia, aby uzyskać parametry konstruktora, a następnie próbuje znaleźć najbliższe dopasowanie przez nazwę tych parametrów konstruktora do właściwości obiektu. Sprawdza także typ właściwości i parametry do dopasowania. Jeśli nie zostanie znalezione dopasowanie, to wartość domyślna zostanie przekazana do tego sparametryzowanego konstruktora.
możesz to sprawdzić za 1 minutę. Ustaw punkt przerwania w konstruktorze –
Nie całkowicie zależy to od faktycznego typu serializacji/deserializacji. XmlSerialization na przykład * robi * używa domyślnego konstruktora. Jest to jednak bezcelowe w stosunku do faktycznego pytania tutaj. – HimBromBeere
Wiesz, że to open source i możesz to sprawdzić na githubie, prawda? –