Serializacja i deserializacja
Program Windows Communication Foundation (WCF) zawiera nowy aparat serializacji, czyli DataContractSerializer. Tłumaczy DataContractSerializer między obiektami .NET Framework i XML w obu kierunkach. W tym temacie wyjaśniono, jak działa serializator.
Podczas serializacji obiektów programu .NET Framework serializator rozumie różne modele programowania serializacji, w tym nowy model kontraktu danych. Aby uzyskać pełną listę obsługiwanych typów, zobacz Typy obsługiwane przez serializator kontraktu danych. Aby zapoznać się z wprowadzeniem do kontraktów danych, zobacz Korzystanie z kontraktów danych.
Podczas deserializacji KODU XML serializator używa XmlReader klas i XmlWriter . Obsługuje XmlDictionaryReader również klasy i XmlDictionaryWriter , aby umożliwić tworzenie zoptymalizowanego kodu XML w niektórych przypadkach, na przykład w przypadku korzystania z formatu XML binarnego WCF.
WCF zawiera również serializator towarzyszący , NetDataContractSerializer. Pomocnik NetDataContractSerializer:
- Nie jest bezpieczny. Aby uzyskać więcej informacji, zobacz Przewodnik po zabezpieczeniach BinaryFormatter.
- Jest podobny do BinaryFormatter seriizatorów i SoapFormatter , ponieważ emituje również nazwy typów programu .NET Framework w ramach serializowanych danych.
- Jest używany, gdy te same typy są współużytkowane na serializacji i kończy deserializacji.
Zarówno DataContractSerializer , jak i NetDataContractSerializer pochodzi z wspólnej klasy bazowej, XmlObjectSerializer.
Ostrzeżenie
Ciągi DataContractSerializer serializuje ciągi zawierające znaki sterujące z wartością szesnastkową poniżej 20 jako jednostek XML. Może to spowodować problem z klientem spoza programu WCF podczas wysyłania takich danych do usługi WCF.
Tworzenie wystąpienia elementu DataContractSerializer
Konstruowanie wystąpienia obiektu DataContractSerializer jest ważnym krokiem. Po zakończeniu budowy nie można zmienić żadnego z ustawień.
Określanie typu głównego
Typ główny jest typem , którego wystąpienia są serializowane lub deserializowane. Obiekt DataContractSerializer ma wiele przeciążeń konstruktora, ale co najmniej należy podać typ główny przy użyciu parametru type
.
Serializator utworzony dla określonego typu głównego nie może służyć do serializacji (lub deserializowania) innego typu, chyba że typ pochodzi z typu głównego. W poniższym przykładzie przedstawiono dwie klasy.
[DataContract]
public class Person
{
// Code not shown.
}
[DataContract]
public class PurchaseOrder
{
// Code not shown.
}
<DataContract()> _
Public Class Person
' Code not shown.
End Class
<DataContract()> _
Public Class PurchaseOrder
' Code not shown.
End Class
Ten kod tworzy wystąpienie DataContractSerializer
klasy , które może służyć tylko do serializacji lub deserializacji wystąpień Person
klasy.
DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
// This can now be used to serialize/deserialize Person but not PurchaseOrder.
Dim dcs As New DataContractSerializer(GetType(Person))
' This can now be used to serialize/deserialize Person but not PurchaseOrder.
Określanie znanych typów
Jeśli polimorfizm jest zaangażowany w typy serializowane, które nie są jeszcze obsługiwane przy użyciu atrybutu KnownTypeAttribute lub innego mechanizmu, lista możliwych znanych typów musi zostać przekazana do konstruktora serializatora przy użyciu parametru knownTypes
. Aby uzyskać więcej informacji na temat znanych typów, zobacz Znane typy kontraktów danych.
W poniższym przykładzie przedstawiono klasę , LibraryPatron
która zawiera kolekcję określonego typu , LibraryItem
czyli . Druga klasa definiuje LibraryItem
typ. Trzecia i cztery klasy (Book
i Newspaper
) dziedziczą z LibraryItem
klasy.
[DataContract]
public class LibraryPatron
{
[DataMember]
public LibraryItem[] borrowedItems;
}
[DataContract]
public class LibraryItem
{
// Code not shown.
}
[DataContract]
public class Book : LibraryItem
{
// Code not shown.
}
[DataContract]
public class Newspaper : LibraryItem
{
// Code not shown.
}
<DataContract()> _
Public Class LibraryPatron
<DataMember()> _
Public borrowedItems() As LibraryItem
End Class
<DataContract()> _
Public Class LibraryItem
' Code not shown.
End Class
<DataContract()> _
Public Class Book
Inherits LibraryItem
' Code not shown.
End Class
<DataContract()> _
Public Class Newspaper
Inherits LibraryItem
' Code not shown.
End Class
Poniższy kod tworzy wystąpienie serializatora przy użyciu parametru knownTypes
.
// Create a serializer for the inherited types using the knownType parameter.
Type[] knownTypes = new Type[] { typeof(Book), typeof(Newspaper) };
DataContractSerializer dcs =
new DataContractSerializer(typeof(LibraryPatron), knownTypes);
// All types are known after construction.
' Create a serializer for the inherited types using the knownType parameter.
Dim knownTypes() As Type = {GetType(Book), GetType(Newspaper)}
Dim dcs As New DataContractSerializer(GetType(LibraryPatron), knownTypes)
' All types are known after construction.
Określanie domyślnej nazwy głównej i przestrzeni nazw
Zwykle, gdy obiekt jest serializowany, domyślna nazwa i przestrzeń nazw najbardziej zewnętrznego elementu XML są określane zgodnie z nazwą kontraktu danych i przestrzenią nazw. Nazwy wszystkich elementów wewnętrznych są określane na podstawie nazw elementów członkowskich danych, a ich przestrzeń nazw jest przestrzenią nazw kontraktu danych. W poniższym przykładzie zestawy Name
i Namespace
wartości w konstruktorach DataContractAttribute klas i DataMemberAttribute .
[DataContract(Name = "PersonContract", Namespace = "http://schemas.contoso.com")]
public class Person2
{
[DataMember(Name = "AddressMember")]
public Address theAddress;
}
[DataContract(Name = "AddressContract", Namespace = "http://schemas.contoso.com")]
public class Address
{
[DataMember(Name = "StreetMember")]
public string street;
}
<DataContract(Name:="PersonContract", [Namespace]:="http://schemas.contoso.com")> _
Public Class Person2
<DataMember(Name:="AddressMember")> _
Public theAddress As Address
End Class
<DataContract(Name:="AddressContract", [Namespace]:="http://schemas.contoso.com")> _
Public Class Address
<DataMember(Name:="StreetMember")> _
Public street As String
End Class
Serializowanie wystąpienia Person
klasy powoduje wygenerowanie kodu XML podobnego do poniższego.
<PersonContract xmlns="http://schemas.contoso.com">
<AddressMember>
<StreetMember>123 Main Street</StreetMember>
</AddressMember>
</PersonContract>
Można jednak dostosować domyślną nazwę i przestrzeń nazw elementu głównego, przekazując wartości rootName
parametrów i rootNamespace
do konstruktora DataContractSerializer . Należy pamiętać, że element rootNamespace
nie ma wpływu na przestrzeń nazw zawartych elementów, które odpowiadają członkom danych. Ma to wpływ tylko na przestrzeń nazw najbardziej zewnętrznego elementu.
Te wartości można przekazać jako ciągi lub wystąpienia XmlDictionaryString klasy, aby umożliwić ich optymalizację przy użyciu binarnego formatu XML.
Ustawianie maksymalnego limitu przydziału obiektów
Niektóre DataContractSerializer
przeciążenia konstruktora mają maxItemsInObjectGraph
parametr . Ten parametr określa maksymalną liczbę obiektów serializatora serializuje lub deserializuje w jednym ReadObject wywołaniu metody. (Metoda zawsze odczytuje jeden obiekt główny, ale ten obiekt może mieć inne obiekty w jego składowych danych. Te obiekty mogą mieć inne obiekty itd.) Wartość domyślna to 65536. Należy pamiętać, że podczas serializacji lub deserializacji tablic każdy wpis tablicy liczy się jako oddzielny obiekt. Należy również pamiętać, że niektóre obiekty mogą mieć dużą reprezentację pamięci, dlatego sam limit przydziału może nie być wystarczający, aby zapobiec atakowi typu "odmowa usługi". Aby uzyskać więcej informacji, zobacz Zagadnienia dotyczące zabezpieczeń danych. Jeśli musisz zwiększyć ten limit przydziału poza wartość domyślną, należy to zrobić zarówno po stronie wysyłania (serializacji) i odbierania (deserializacji), ponieważ dotyczy zarówno podczas odczytywania i zapisywania danych.
Rundy
Round trip występuje, gdy obiekt jest deserializowany i ponownie serializowany w jednej operacji. W związku z tym przechodzi on z kodu XML do wystąpienia obiektu, a następnie ponownie do strumienia XML.
Niektóre DataContractSerializer
przeciążenia konstruktora mają ignoreExtensionDataObject
parametr , który jest domyślnie ustawiony na false
wartość . W tym trybie domyślnym dane mogą być wysyłane w obie strony z nowszej wersji kontraktu danych za pośrednictwem starszej wersji i z powrotem do nowszej wersji bez utraty, o ile kontrakt danych implementuje IExtensibleDataObject interfejs. Załóżmy na przykład, że wersja 1 kontraktu danych zawiera Name
elementy członkowskie iPhoneNumber
, a wersja 2 dodaje element członkowskiNickname
.Person
Jeśli IExtensibleDataObject
jest zaimplementowana, podczas wysyłania informacji z wersji 2 do wersji 1 Nickname
dane są przechowywane, a następnie ponownie emitowane, gdy dane są serializowane ponownie; w związku z tym żadne dane nie zostaną utracone w obie strony. Aby uzyskać więcej informacji, zobacz Przekazywanie zgodnych kontraktów danych i przechowywanie wersji kontraktów danych.
Problemy dotyczące ważności zabezpieczeń i schematu z rundami
Podróże okrężne mogą mieć wpływ na bezpieczeństwo. Na przykład deserializowanie i przechowywanie dużych ilości danych nadmiarowych może stanowić zagrożenie bezpieczeństwa. Mogą wystąpić obawy dotyczące ponownego emitowania tych danych, że nie ma możliwości zweryfikowania, zwłaszcza jeśli są zaangażowane podpisy cyfrowe. Na przykład w poprzednim scenariuszu punkt końcowy w wersji 1 może podpisować wartość zawierającą Nickname
złośliwe dane. Na koniec mogą występować obawy dotyczące ważności schematu: punkt końcowy może zawsze emitować dane, które ściśle przestrzegają określonego kontraktu, a nie żadnych dodatkowych wartości. W poprzednim przykładzie kontrakt punktu końcowego w wersji 1 mówi, że emituje tylko Name
wartości i PhoneNumber
, a jeśli jest używana walidacja schematu, emitując dodatkową Nickname
wartość, powoduje niepowodzenie walidacji.
Włączanie i wyłączanie rund
Aby wyłączyć rundy, nie implementuj interfejsu IExtensibleDataObject . Jeśli nie masz kontroli nad typami, ustaw ignoreExtensionDataObject
parametr , aby true
osiągnąć ten sam efekt.
Zachowywanie grafu obiektów
Zwykle serializator nie dba o tożsamość obiektu, jak w poniższym kodzie.
[DataContract]
public class PurchaseOrder
{
[DataMember]
public Address billTo;
[DataMember]
public Address shipTo;
}
[DataContract]
public class Address
{
[DataMember]
public string street;
}
<DataContract()> _
Public Class PurchaseOrder
<DataMember()> _
Public billTo As Address
<DataMember()> _
Public shipTo As Address
End Class
<DataContract()> _
Public Class Address
<DataMember()> _
Public street As String
End Class
Poniższy kod tworzy zamówienie zakupu.
// Construct a purchase order:
Address adr = new Address();
adr.street = "123 Main St.";
PurchaseOrder po = new PurchaseOrder();
po.billTo = adr;
po.shipTo = adr;
' Construct a purchase order:
Dim adr As New Address()
adr.street = "123 Main St."
Dim po As New PurchaseOrder()
po.billTo = adr
po.shipTo = adr
Zwróć uwagę, że billTo
pola i shipTo
są ustawione na to samo wystąpienie obiektu. Wygenerowany kod XML duplikuje jednak zduplikowane informacje i wygląda podobnie do poniższego kodu XML.
<PurchaseOrder>
<billTo><street>123 Main St.</street></billTo>
<shipTo><street>123 Main St.</street></shipTo>
</PurchaseOrder>
Jednak takie podejście ma następujące cechy, które mogą być niepożądane:
Wydajność. Replikowanie danych jest nieefektywne.
Odwołania cykliczne. Jeśli obiekty odwołują się do siebie, nawet za pośrednictwem innych obiektów, serializowanie przez replikację powoduje nieskończoną pętlę. (Serializator zgłasza wyjątek SerializationException , jeśli tak się stanie).
Semantyka. Czasami ważne jest zachowanie faktu, że dwa odwołania są do tego samego obiektu, a nie do dwóch identycznych obiektów.
Z tych powodów niektóre DataContractSerializer
przeciążenia konstruktorów mają preserveObjectReferences
parametr (wartość domyślna to false
). Gdy ten parametr ma wartość true
, jest używana specjalna metoda kodowania odwołań do obiektów, która jest używana tylko w programie WCF. Gdy ustawiono true
wartość , przykładowy kod XML będzie teraz podobny do poniższego.
<PurchaseOrder ser:id="1">
<billTo ser:id="2"><street ser:id="3">123 Main St.</street></billTo>
<shipTo ser:ref="2"/>
</PurchaseOrder>
Przestrzeń nazw "ser" odnosi się do standardowej przestrzeni nazw serializacji, http://schemas.microsoft.com/2003/10/Serialization/
. Każda część danych jest serializowana tylko raz i podana liczba identyfikatorów, a następnie używa wyniku odwołania do już serializowanych danych.
Ważne
Jeśli atrybuty "id" i "ref" są obecne w kontrakcie XMLElement
danych, atrybut "ref" jest honorowany, a atrybut "id" jest ignorowany.
Ważne jest, aby zrozumieć ograniczenia tego trybu:
Kod XML, który
DataContractSerializer
tworzy zpreserveObjectReferences
ustawionym wartościątrue
, nie jest możliwy do współdziałania z innymi technologiami i można uzyskać do niego dostęp tylko przez inneDataContractSerializer
wystąpienie, również z ustawionympreserveObjectReferences
natrue
wartość .Brak obsługi metadanych (schematu) dla tej funkcji. Wygenerowany schemat jest prawidłowy tylko w przypadku, gdy
preserveObjectReferences
parametr ma wartośćfalse
.Ta funkcja może spowodować spowolnienie procesu serializacji i deserializacji. Chociaż dane nie muszą być replikowane, należy wykonać dodatkowe porównania obiektów w tym trybie.
Uwaga
Po włączeniu preserveObjectReferences
trybu jest szczególnie ważne, aby ustawić maxItemsInObjectGraph
wartość na prawidłowy limit przydziału. Ze względu na sposób obsługi tablic w tym trybie można łatwo utworzyć przez osobę atakującą małą złośliwą wiadomość, która powoduje duże zużycie pamięci ograniczone tylko przez limit przydziału maxItemsInObjectGraph
.
Określanie zastępczego kontraktu danych
Niektóre DataContractSerializer
przeciążenia konstruktora mają dataContractSurrogate
parametr , który może być ustawiony na null
wartość . W przeciwnym razie można go użyć do określenia zastępczego kontraktu IDataContractSurrogate danych, który jest typem implementujący interfejs. Następnie można użyć interfejsu, aby dostosować proces serializacji i deserializacji. Aby uzyskać więcej informacji, zobacz Data Contract Surrogates (Zastępcze kontrakty danych).
Serializacja
Poniższe informacje dotyczą każdej klasy dziedziczonej XmlObjectSerializerz klasy , w tym DataContractSerializer klas i NetDataContractSerializer .
Prosta serializacja
Najbardziej podstawowym sposobem serializacji obiektu jest przekazanie go do WriteObject metody . Istnieją trzy przeciążenia, po jednym do zapisu w Streamobiekcie , , XmlWriterlub XmlDictionaryWriter. W przypadku Stream przeciążenia dane wyjściowe są xml w kodowaniu UTF-8. XmlDictionaryWriter Przy przeciążeniu serializator optymalizuje dane wyjściowe pliku XML binarnego.
W przypadku korzystania z WriteObject metody serializator używa domyślnej nazwy i przestrzeni nazw dla elementu otoki i zapisuje go wraz z zawartością (zobacz poprzednią sekcję "Określanie domyślnej nazwy głównej i przestrzeni nazw").
W poniższym przykładzie pokazano pisanie za pomocą elementu XmlDictionaryWriter.
Person p = new Person();
DataContractSerializer dcs =
new DataContractSerializer(typeof(Person));
XmlDictionaryWriter xdw =
XmlDictionaryWriter.CreateTextWriter(someStream,Encoding.UTF8 );
dcs.WriteObject(xdw, p);
Dim p As New Person()
Dim dcs As New DataContractSerializer(GetType(Person))
Dim xdw As XmlDictionaryWriter = _
XmlDictionaryWriter.CreateTextWriter(someStream, Encoding.UTF8)
dcs.WriteObject(xdw, p)
Spowoduje to wygenerowanie kodu XML podobnego do poniższego.
<Person>
<Name>Jay Hamlin</Name>
<Address>123 Main St.</Address>
</Person>
Serializacja krok po kroku
WriteStartObjectUżyj metod , WriteObjectContenti WriteEndObject , aby zapisać element końcowy, zapisać zawartość obiektu i zamknąć odpowiednio element otoki.
Uwaga
Nie Stream ma przeciążeń tych metod.
Ta serializacji krok po kroku ma dwa typowe zastosowania. Jednym z nich jest wstawianie zawartości, takiej jak atrybuty lub komentarze między WriteStartObject
i WriteObjectContent
, jak pokazano w poniższym przykładzie.
dcs.WriteStartObject(xdw, p);
xdw.WriteAttributeString("serializedBy", "myCode");
dcs.WriteObjectContent(xdw, p);
dcs.WriteEndObject(xdw);
dcs.WriteStartObject(xdw, p)
xdw.WriteAttributeString("serializedBy", "myCode")
dcs.WriteObjectContent(xdw, p)
dcs.WriteEndObject(xdw)
Spowoduje to wygenerowanie kodu XML podobnego do poniższego.
<Person serializedBy="myCode">
<Name>Jay Hamlin</Name>
<Address>123 Main St.</Address>
</Person>
Innym typowym zastosowaniem jest unikanie używania WriteStartObject i WriteEndObject całkowitego pisania własnego niestandardowego elementu otoki (a nawet pomijania pisania otoki), jak pokazano w poniższym kodzie.
xdw.WriteStartElement("MyCustomWrapper");
dcs.WriteObjectContent(xdw, p);
xdw.WriteEndElement();
xdw.WriteStartElement("MyCustomWrapper")
dcs.WriteObjectContent(xdw, p)
xdw.WriteEndElement()
Spowoduje to wygenerowanie kodu XML podobnego do poniższego.
<MyCustomWrapper>
<Name>Jay Hamlin</Name>
<Address>123 Main St.</Address>
</MyCustomWrapper>
Uwaga
Użycie serializacji krok po kroku może spowodować nieprawidłowy kod XML schematu.
Deserializacji
Poniższe informacje dotyczą każdej klasy dziedziczonej XmlObjectSerializerz klasy , w tym DataContractSerializer klas i NetDataContractSerializer .
Najbardziej podstawowym sposobem deserializacji obiektu jest wywołanie jednego z ReadObject przeciążeń metody. Istnieją trzy przeciążenia, po jednym do odczytu z XmlDictionaryReader, , XmlReader
lub Stream
. Należy pamiętać, że Stream
przeciążenie tworzy tekstowy XmlDictionaryReader , który nie jest chroniony przez żadne limity przydziału i powinien być używany tylko do odczytywania zaufanych danych.
Należy również pamiętać, że obiekt ReadObject
zwracany przez metodę musi być rzutowy do odpowiedniego typu.
Poniższy kod tworzy wystąpienie DataContractSerializer klasy i XmlDictionaryReader, a następnie deserializuje Person
wystąpienie.
DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
FileStream fs = new FileStream(path, FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
Person p = (Person)dcs.ReadObject(reader);
Dim dcs As New DataContractSerializer(GetType(Person))
Dim fs As New FileStream(path, FileMode.Open)
Dim reader As XmlDictionaryReader = _
XmlDictionaryReader.CreateTextReader(fs, New XmlDictionaryReaderQuotas())
Dim p As Person = CType(dcs.ReadObject(reader), Person)
Przed wywołaniem ReadObject metody umieść czytnik XML w elemecie otoki lub w węźle innym niż zawartość poprzedzającym element otoki. W tym celu można wywołać metodę Read lub jej wyprowadzenie i przetestować metodę XmlReaderNodeType, jak pokazano w poniższym kodzie.
DataContractSerializer ser = new DataContractSerializer(typeof(Person),
"Customer", @"http://www.contoso.com");
FileStream fs = new FileStream(path, FileMode.Open);
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (ser.IsStartObject(reader))
{
Console.WriteLine("Found the element");
Person p = (Person)ser.ReadObject(reader);
Console.WriteLine("{0} {1} id:{2}",
p.Name , p.Address);
}
Console.WriteLine(reader.Name);
break;
}
}
Dim ser As New DataContractSerializer(GetType(Person), "Customer", "http://www.contoso.com")
Dim fs As New FileStream(path, FileMode.Open)
Dim reader As XmlDictionaryReader = XmlDictionaryReader.CreateTextReader(fs, New XmlDictionaryReaderQuotas())
While reader.Read()
Select Case reader.NodeType
Case XmlNodeType.Element
If ser.IsStartObject(reader) Then
Console.WriteLine("Found the element")
Dim p As Person = CType(ser.ReadObject(reader), Person)
Console.WriteLine("{0} {1}", _
p.Name, p.Address)
End If
Console.WriteLine(reader.Name)
End Select
End While
Przed przekazaniem czytnika do elementu ReadObject
otoki można odczytać atrybuty .
W przypadku korzystania z jednego z prostych ReadObject
przeciążeń deserializator wyszukuje domyślną nazwę i przestrzeń nazw w elemplecie otoki (zobacz poprzednią sekcję "Określanie domyślnej nazwy głównej i przestrzeni nazw") i zgłasza wyjątek, jeśli znajdzie nieznany element. W poprzednim przykładzie oczekiwany <Person>
jest element otoki. Metoda IsStartObject jest wywoływana w celu sprawdzenia, czy czytnik jest umieszczony w elemecie o nazwie zgodnie z oczekiwaniami.
Istnieje sposób wyłączenia sprawdzania nazwy elementu otoki; niektóre przeciążenia ReadObject
metody przyjmują parametr verifyObjectName
logiczny , który jest domyślnie ustawiony na true
wartość . Po ustawieniu false
wartości parametru nazwa i przestrzeń nazw elementu otoki jest ignorowana. Jest to przydatne w przypadku odczytywania kodu XML napisanego przy użyciu opisanego wcześniej mechanizmu serializacji krok po kroku.
Korzystanie z narzędzia NetDataContractSerializer
Podstawową różnicą między elementami DataContractSerializer
i NetDataContractSerializer jest to, że DataContractSerializer
używa nazw kontraktów danych, podczas gdy NetDataContractSerializer
dane wyjściowe zawierają pełne nazwy zestawów i typów programu .NET Framework w serializowanym formacie XML. Oznacza to, że dokładnie te same typy muszą być współdzielone między punktami końcowymi serializacji i deserializacji. Oznacza to, że znany mechanizm typów nie jest wymagany, NetDataContractSerializer
ponieważ dokładne typy do deserializacji są zawsze znane.
Może jednak wystąpić kilka problemów:
Zabezpieczenia. Każdy typ znaleziony w pliku XML, który jest deserializowany, jest ładowany. Można to wykorzystać, aby wymusić ładowanie złośliwych typów.
NetDataContractSerializer
Używanie elementu z niezaufanymi danymi powinno odbywać się tylko wtedy, gdy jest używany binder serializacji (przy użyciu Binder właściwości lub parametru konstruktora). Binder zezwala na ładowanie tylko bezpiecznych typów. Mechanizm binder jest identyczny z mechanizmem używanym System.Runtime.Serialization w przestrzeni nazw.Przechowywanie wersji. Używanie pełnych nazw typów i zestawów w kodzie XML poważnie ogranicza sposób, w jaki typy mogą być wersjonowane. Nie można zmienić następujących elementów: nazwy typów, przestrzenie nazw, nazwy zestawów i wersje zestawów. AssemblyFormat Ustawienie właściwości lub parametru konstruktora na Simple wartość zamiast domyślnej Full wartości zezwala na zmiany wersji zestawu, ale nie dla ogólnych typów parametrów.
Współdziałanie. Ponieważ nazwy typów i zestawów programu .NET Framework są zawarte w kodzie XML, platformy inne niż program .NET Framework nie mogą uzyskać dostępu do danych wynikowych.
Wydajność. Zapisywanie typów i nazw zestawów znacznie zwiększa rozmiar wynikowego kodu XML.
Ten mechanizm jest podobny do serializacji binarnej lub SOAP używanej przez komunikacji zdalną programu .NET Framework (w szczególności i BinaryFormatterSoapFormatter).
Użycie elementu NetDataContractSerializer
jest podobne do używania elementu DataContractSerializer
, z następującymi różnicami:
Konstruktory nie wymagają określenia typu głównego. Można serializować dowolny typ przy użyciu tego samego wystąpienia klasy
NetDataContractSerializer
.Konstruktory nie akceptują listy znanych typów. Znany mechanizm typów jest niepotrzebny, jeśli nazwy typów są serializowane w formacie XML.
Konstruktory nie akceptują zastępczego kontraktu danych. Zamiast tego akceptują ISurrogateSelector parametr o nazwie
surrogateSelector
(który mapuje na SurrogateSelector właściwość). Jest to starszy mechanizm zastępczy.Konstruktory akceptują parametr o nazwie
assemblyFormat
FormatterAssemblyStyle , który mapuje na AssemblyFormat właściwość . Jak wspomniano wcześniej, może to służyć do zwiększenia możliwości przechowywania wersji serializatora. Jest to identyczne z mechanizmem FormatterAssemblyStyle serializacji binarnej lub SOAP.Konstruktory akceptują StreamingContext parametr o nazwie
context
, który mapuje na Context właściwość. Służy to do przekazywania informacji do typów serializacji. To użycie jest identyczne z mechanizmem używanym StreamingContext w innych System.Runtime.Serialization klasach.Metody Serialize i Deserialize są aliasami metod WriteObject i ReadObject . Istnieją one, aby zapewnić bardziej spójny model programowania z serializacji binarnej lub SOAP.
Aby uzyskać więcej informacji na temat tych funkcji, zobacz Serializacja binarna.
Formaty XML, których NetDataContractSerializer
używa i DataContractSerializer
są zwykle niezgodne. Oznacza to, że próba serializacji przy użyciu jednego z tych serializatorów i deserializacji z drugą nie jest obsługiwanym scenariuszem.
Należy również pamiętać, że element NetDataContractSerializer
nie generuje pełnej nazwy zestawu i typu .NET Framework dla każdego węzła na grafie obiektów. Dane wyjściowe są wyświetlane tylko w przypadku, gdy są niejednoznaczne. Oznacza to, że zwraca dane wyjściowe na poziomie obiektu głównego i dla wszystkich przypadków polimorficznych.