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ę , LibraryPatronktóra zawiera kolekcję określonego typu , LibraryItemczyli . 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 truewartość , 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 XMLElementdanych, atrybut "ref" jest honorowany, a atrybut "id" jest ignorowany.

Ważne jest, aby zrozumieć ograniczenia tego trybu:

  • Kod XML, który DataContractSerializer tworzy z preserveObjectReferences 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 inne DataContractSerializer wystąpienie, również z ustawionym preserveObjectReferences na truewartość .

  • 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 nullwartość . 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, , XmlReaderlub 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 ReadObjectotoki 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 verifyObjectNamelogiczny , który jest domyślnie ustawiony na true wartość . Po ustawieniu falsewartoś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 assemblyFormatFormatterAssemblyStyle , 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.

Zobacz też