Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Eine Auflistung ist eine Liste von Elementen eines bestimmten Typs. In .NET Framework können solche Listen mithilfe von Arrays oder einer Vielzahl anderer Typen dargestellt werden (Generic List, Generic BindingList<T>, StringCollectionoder ArrayList). Beispielsweise kann eine Sammlung eine Liste der Adressen für einen bestimmten Kunden enthalten. Diese Auflistungen werden unabhängig vom tatsächlichen Typ als Listensammlungen bezeichnet.
Eine spezielle Form der Auflistung ist vorhanden, die eine Zuordnung zwischen einem Element (dem Schlüssel) und einem anderen (dem "Wert") darstellt. In .NET Framework werden diese durch Typen wie Hashtable z. B. und das generische Wörterbuch dargestellt. Eine Zuordnungssammlung kann z. B. eine Stadt ("Schlüssel") der zugehörigen Bevölkerung ("Wert") zuordnen. Diese Auflistungen werden unabhängig vom tatsächlichen Typ als Wörterbuchsammlungen bezeichnet.
Sammlungen erhalten besondere Behandlung im Datenvertragsmodell.
Typen, die die IEnumerable Schnittstelle implementieren, einschließlich Arrays und generischen Auflistungen, werden als Sammlungen erkannt. Von diesen Typen, die die IDictionary Oder generische IDictionary<TKey,TValue> Schnittstellen implementieren, sind Wörterbuchsammlungen; alle anderen sind Listensammlungen.
Weitere Anforderungen an Sammlungstypen, z. B. das Aufrufen einer Methode Add und ein parameterloser Konstruktor, werden in den folgenden Abschnitten ausführlich erläutert. Dadurch wird sichergestellt, dass Sammlungstypen sowohl serialisiert als auch deserialisiert werden können. Dies bedeutet, dass einige Auflistungen nicht direkt unterstützt werden, z. B. "Generic ReadOnlyCollection<T> " (da sie keinen parameterlosen Konstruktor aufweist). Informationen zur Umgehung dieser Einschränkungen finden Sie im Abschnitt "Verwenden von Sammlungsschnittstellentypen und Read-Only Sammlungen" weiter unten in diesem Thema.
Die in Sammlungen enthaltenen Typen müssen Datenvertragstypen sein oder anderweitig serialisierbar sein. Weitere Informationen finden Sie unter Typen, die vom Serializer für den Datenvertrag unterstützt werden.
Weitere Informationen dazu, was ist und was nicht als gültige Sammlung betrachtet wird, sowie darüber, wie Sammlungen serialisiert werden, finden Sie in den Informationen zum Serialisieren von Sammlungen im Abschnitt "Erweiterte Sammlungsregeln" dieses Themas.
Austauschbare Sammlungen
Alle Listensammlungen des gleichen Typs gelten als denselben Datenvertrag zu haben (es sei denn, sie werden mithilfe des CollectionDataContractAttribute-Attributes angepasst, wie später in diesem Thema erläutert). So sind beispielsweise die folgenden Datenverträge gleichwertig.
[DataContract(Name = "PurchaseOrder")]
public class PurchaseOrder1
{
[DataMember]
public string customerName;
[DataMember]
public Collection<Item> items;
[DataMember]
public string[] comments;
}
[DataContract(Name = "PurchaseOrder")]
public class PurchaseOrder2
{
[DataMember]
public string customerName;
[DataMember]
public List<Item> items;
[DataMember]
public BindingList<string> comments;
}
<DataContract(Name:="PurchaseOrder")>
Public Class PurchaseOrder1
<DataMember()>
Public customerName As String
<DataMember()>
Public items As Collection(Of Item)
<DataMember()>
Public comments() As String
End Class
<DataContract(Name:="PurchaseOrder")>
Public Class PurchaseOrder2
<DataMember()>
Public customerName As String
<DataMember()>
Public items As List(Of Item)
<DataMember()>
Public comments As BindingList(Of String)
End Class
Beide Datenverträge führen zu XML ähnlich dem folgenden Code.
<PurchaseOrder>
<customerName>...</customerName>
<items>
<Item>...</Item>
<Item>...</Item>
<Item>...</Item>
...
</items>
<comments>
<string>...</string>
<string>...</string>
<string>...</string>
...
</comments>
</PurchaseOrder>
Mithilfe der Sammlungstauschbarkeit können Sie z. B. einen sammlungstyp verwenden, der für die Leistung auf dem Server optimiert ist, und einen Sammlungstyp, der an Benutzeroberflächenkomponenten auf dem Client gebunden werden soll.
Ähnlich wie bei Listensammlungen werden alle Wörterbuchsammlungen mit demselben Schlüssel- und Werttyp als derselbe Datenkontrakt betrachtet, es sei denn, sie werden durch das CollectionDataContractAttribute-Attribut angepasst.
Es geht nur um den Datentyp des Datenvertrags, soweit es um die Sammlungsäquivalente geht, nicht um .NET-Typen. Das heißt, eine Sammlung von Type1 wird als Äquivalent zu einer Sammlung von Type2 betrachtet, wenn Type1 und Type2 über gleichwertige Datenverträge verfügen.
Nicht generische Auflistungen gelten als derselbe Datenvertrag wie generische Auflistungen vom Typ Object. (Beispielsweise sind die Datenverträge für ArrayList und Generic List<T> von Object identisch.)
Verwenden von Sammlungsschnittstellentypen und schreibgeschützten Sammlungen
Sammlungsschnittstellentypen (IEnumerable, IDictionarygenerische IDictionary<TKey,TValue>oder von diesen Schnittstellen abgeleitete Schnittstellen) werden auch als Sammlungsdatenverträge betrachtet, die den Sammlungsdatenverträgen für tatsächliche Sammlungstypen entsprechen. Daher ist es möglich, den Typ zu deklarieren, der als Sammlungsschnittstellentyp serialisiert wird, und die Ergebnisse sind identisch mit der Verwendung eines tatsächlichen Sammlungstyps. Beispielsweise sind die folgenden Datenverträge gleichwertig.
[DataContract(Name="Customer")]
public class Customer1
{
[DataMember]
public string customerName;
[DataMember]
public Collection<Address> addresses;
}
[DataContract(Name="Customer")]
public class Customer2
{
[DataMember]
public string customerName;
[DataMember]
public ICollection<Address> addresses;
}
<DataContract(Name:="Customer")>
Public Class Customer1
<DataMember()>
Public customerName As String
<DataMember()>
Public addresses As Collection(Of Address)
End Class
<DataContract(Name:="Customer")>
Public Class Customer2
<DataMember()>
Public customerName As String
<DataMember()>
Public addresses As ICollection(Of Address)
End Class
Wenn der deklarierte Typ eine Schnittstelle ist, kann der derzeit verwendete Instanzentyp während der Serialisierung ein beliebiger Typ sein, der diese Schnittstelle implementiert. Die zuvor beschriebenen Einschränkungen (mit einem parameterlosen Konstruktor und einer Add Methode) gelten nicht. Sie können z. B. Adressen in Customer2 auf eine Instanz von "Generic ReadOnlyCollection<T> of Address" festlegen, obwohl Sie ein Datenmememm des Typs "Generic" ReadOnlyCollection<T>nicht direkt deklarieren können.
Wenn der deklarierte Typ eine Schnittstelle ist, wählt das Serialisierungsmodul während der Deserialisierung einen Typ aus, der die deklarierte Schnittstelle implementiert, und der Typ wird instanziiert. Der bekannte Typenmechanismus (beschrieben in bekannten Datenvertragstypen) hat hier keine Auswirkung; Die Auswahl des Typs ist in WCF integriert.
Anpassen von Sammlungstypen
Sie können Sammlungstypen mithilfe des CollectionDataContractAttribute Attributs anpassen, das mehrere Verwendungen hat.
Beachten Sie, dass das Anpassen von Sammlungstypen die Austauschbarkeit der Sammlung beeinträchtigt, daher empfiehlt es sich im Allgemeinen, das Anwenden dieses Attributs nach Möglichkeit zu vermeiden. Weitere Informationen zu diesem Problem finden Sie im Abschnitt "Erweiterte Sammlungsregeln" weiter unten in diesem Thema.
Benennung des Sammlungsdatenvertrags
Die Regeln für die Benennung von Sammlungstypen ähneln denen für die Benennung regulärer Datentypen, wie unter "Datenvertragsnamen" beschrieben, obwohl einige wichtige Unterschiede bestehen:
Das CollectionDataContractAttribute Attribut wird verwendet, um den Namen anstelle des DataContractAttribute Attributs anzupassen. Das CollectionDataContractAttribute-Attribut hat auch
Name- undNamespace-Eigenschaften.Wenn das CollectionDataContractAttribute Attribut nicht angewendet wird, hängen der Standardname und der Namespace für Sammlungstypen von den Namen und Namespaces von Typen ab, die in der Auflistung enthalten sind. Sie werden nicht vom Namen und dem Namespace des Sammlungstyps selbst beeinflusst. Ein Beispiel finden Sie unter den folgenden Typen.
public CustomerList1 : Collection<string> {} public StringList1 : Collection<string> {}
Der Name des Datenvertrags beider Typen lautet "ArrayOfstring" und nicht "CustomerList1" oder "StringList1". Dies bedeutet, dass die Serialisierung eines dieser Typen auf der Stammebene XML ähnlich dem folgenden Code liefert.
<ArrayOfstring>
<string>...</string>
<string>...</string>
<string>...</string>
...
</ArrayOfstring>
Diese Benennungsregel wurde ausgewählt, um sicherzustellen, dass alle nicht angepassten Typen, die eine Liste von Zeichenfolgen darstellen, denselben Datenvertrag und die XML-Darstellung aufweisen. Dies ermöglicht die Austauschbarkeit der Sammlung. In diesem Beispiel sind CustomerList1 und StringList1 vollständig austauschbar.
Wenn das CollectionDataContractAttribute Attribut angewendet wird, wird die Auflistung jedoch zu einem benutzerdefinierten Sammlungsdatenvertrag, auch wenn keine Eigenschaften für das Attribut festgelegt werden. Der Name und der Namespace des Sammlungsdatenvertrags hängen dann vom Sammlungstyp selbst ab. Ein Beispiel finden Sie unter dem folgenden Typ.
[CollectionDataContract]
public class CustomerList2 : Collection<string> {}
<CollectionDataContract()>
Public Class CustomerList2
Inherits Collection(Of String)
End Class
Bei der Serialisierung ähnelt der resultierende XML-Code folgendem.
<CustomerList2>
<string>...</string>
<string>...</string>
<string>...</string>
...
</CustomerList2>
Beachten Sie, dass dies nicht mehr der XML-Darstellung der nicht angepassten Typen entspricht.
Sie können die Benennung durch die Eigenschaften
NameundNamespaceweiter anpassen. Siehe folgende Klasse.[CollectionDataContract(Name="cust_list")] public class CustomerList3 : Collection<string> {}<CollectionDataContract(Name:="cust_list")> Public Class CustomerList3 Inherits Collection(Of String) End Class
Der resultierende XML-Code ähnelt der folgenden.
<cust_list>
<string>...</string>
<string>...</string>
<string>...</string>
...
</cust_list>
Weitere Informationen finden Sie im Abschnitt "Erweiterte Sammlungsregeln" weiter unten in diesem Thema.
Anpassen des sich wiederholenden Elementnamens in Listensammlungen
Listensammlungen enthalten wiederholte Einträge. Normalerweise wird jeder wiederholte Eintrag als ein Element dargestellt, das entsprechend dem Datenvertragsnamen des in der Sammlung enthaltenen Typs benannt ist.
In den CustomerList Beispielen enthielten die Auflistungen Zeichenfolgen. Der Name des Datenvertrags für den Zeichenfolgengrundtyp lautet "string", sodass das wiederholte Element "<string>" lautet.
Mithilfe der ItemName Eigenschaft für das CollectionDataContractAttribute Attribut kann dieser wiederholte Elementname jedoch angepasst werden. Ein Beispiel finden Sie unter dem folgenden Typ.
[CollectionDataContract(ItemName="customer")]
public class CustomerList4 : Collection<string> {}
<CollectionDataContract(ItemName:="customer")>
Public Class CustomerList4
Inherits Collection(Of String)
End Class
Der resultierende XML-Code ähnelt der folgenden.
<CustomerList4>
<customer>...</customer>
<customer>...</customer>
<customer>...</customer>
...
</CustomerList4>
Der Namespace des wiederholten Elements ist immer identisch mit dem Namespace des Sammlungsdatenvertrags, der mithilfe der Namespace Eigenschaft angepasst werden kann, wie zuvor beschrieben.
Anpassen von Wörterbuchsammlungen
Wörterbuchsammlungen sind im Wesentlichen Listen mit Einträgen, wobei jeder Eintrag über einen Schlüssel gefolgt von einem Wert verfügt. Genau wie bei regulären Listen können Sie den Elementnamen ändern, der dem wiederholten Element entspricht, indem Sie die ItemName Eigenschaft verwenden.
Darüber hinaus können Sie die Elementnamen ändern, die den Schlüssel und den Wert darstellen, indem Sie die KeyName Eigenschaften verwenden ValueName . Die Namespaces für diese Elemente sind identisch mit dem Namespace des Sammlungsdatenvertrags.
Ein Beispiel finden Sie unter dem folgenden Typ.
[CollectionDataContract
(Name = "CountriesOrRegionsWithCapitals",
ItemName = "entry",
KeyName = "countryorregion",
ValueName = "capital")]
public class CountriesOrRegionsWithCapitals2 : Dictionary<string, string> { }
<CollectionDataContract(Name:="CountriesOrRegionsWithCapitals",
ItemName:="entry", KeyName:="countryorregion",
ValueName:="capital")>
Public Class CountriesOrRegionsWithCapitals2
Inherits Dictionary(Of String, String)
End Class
Bei der Serialisierung ähnelt der resultierende XML-Code folgendem.
<CountriesOrRegionsWithCapitals>
<entry>
<countryorregion>USA</countryorregion>
<capital>Washington</capital>
</entry>
<entry>
<countryorregion>France</countryorregion>
<capital>Paris</capital>
</entry>
...
</CountriesOrRegionsWithCapitals>
Weitere Informationen zu Wörterbuchsammlungen finden Sie im Abschnitt "Erweiterte Sammlungsregeln" weiter unten in diesem Thema.
Sammlungen und bekannte Typen
Sie müssen keine Sammlungstypen zu bekannten Typen hinzufügen, wenn sie anstelle anderer Auflistungen oder Sammlungsschnittstellen polymorph verwendet werden. Wenn Sie z. B. ein Datenelement vom Typ IEnumerable deklarieren und verwenden, um eine Instanz von ArrayList zu senden, müssen Sie ArrayList nicht zu bekannten Typen hinzufügen.
Wenn Sie Sammlungen polymorph anstelle von Nicht-Sammlungstypen verwenden, müssen sie bekannten Typen hinzugefügt werden. Wenn Sie z. B. ein Datenmitglied vom Typ Object deklarieren und verwenden, um eine Instanz von ArrayList zu senden, fügen Sie ArrayList zu den bekannten Typen hinzu.
Dies ermöglicht es Ihnen nicht, eine äquivalente Sammlung polymorph zu serialisieren. Wenn Sie beispielsweise der Liste bekannter Typen im vorherigen Beispiel hinzufügen ArrayList , können Sie die Array of Object Klasse nicht zuweisen, auch wenn sie über einen entsprechenden Datenvertrag verfügt. Dies unterscheidet sich nicht vom normalen Verhalten bekannter Typen bei der Serialisierung für Nicht-Sammlungs-Typen, aber es ist besonders wichtig, dies im Fall von Sammlungen zu verstehen, da es sehr häufig vorkommt, dass Sammlungen gleichwertig sind.
Während der Serialisierung kann nur ein Typ in einem bestimmten Bereich für einen bestimmten Datenvertrag bekannt sein, und gleichwertige Sammlungen verfügen alle über dieselben Datenverträge. Dies bedeutet, dass Sie im vorherigen Beispiel ArrayList und Array of Object nicht beide im selben Bereich zu bekannten Typen hinzufügen können. Wiederum entspricht dies dem Verhalten bekannter Typen bei Nicht-Sammlungstypen, ist jedoch besonders wichtig, wenn es um das Verständnis für Sammlungen geht.
Bekannte Typen können auch für Inhalte von Sammlungen erforderlich sein. Wenn eine ArrayList tatsächlich Instanzen von Type1 und Type2 enthält, sollten beide Typen zu den bekannten Typen hinzugefügt werden.
Das folgende Beispiel zeigt ein ordnungsgemäß konstruiertes Objektdiagramm mit Auflistungen und bekannten Typen. (Das Beispiel ist frei erfunden, da Sie in einer echten Anwendung normalerweise die folgenden Datenmember nicht als Objectdefinieren und daher auch keine Probleme mit bekannten Typen/Polymorphie auftreten würden.)
[DataContract]
public class Employee
{
[DataMember]
public string name = "John Doe";
[DataMember]
public Payroll payrollRecord;
[DataMember]
public Training trainingRecord;
}
[DataContract]
[KnownType(typeof(int[]))] //required because int[] is used polymorphically
[KnownType(typeof(ArrayList))] //required because ArrayList is used polymorphically
public class Payroll
{
[DataMember]
public object salaryPayments = new int[12];
//float[] not needed in known types because polymorphic assignment is to another collection type
[DataMember]
public IEnumerable<float> stockAwards = new float[12];
[DataMember]
public object otherPayments = new ArrayList();
}
[DataContract]
[KnownType(typeof(List<object>))]
//required because List<object> is used polymorphically
//does not conflict with ArrayList above because it's a different scope,
//even though it's the same data contract
[KnownType(typeof(InHouseTraining))] //Required if InHouseTraining can be used in the collection
[KnownType(typeof(OutsideTraining))] //Required if OutsideTraining can be used in the collection
public class Training
{
[DataMember]
public object training = new List<object>();
}
[DataContract]
public class InHouseTraining
{
//code omitted
}
[DataContract]
public class OutsideTraining
{
//code omitted
}
<DataContract()>
Public Class Employee
<DataMember()>
Public name As String = "John Doe"
<DataMember()>
Public payrollRecord As Payroll
<DataMember()>
Public trainingRecord As Training
End Class
<DataContract(), KnownType(GetType(Integer())), KnownType(GetType(ArrayList))>
Public Class Payroll
<DataMember()>
Public salaryPayments As Object = New Integer(11) {}
'float[] not needed in known types because polymorphic assignment is to another collection type
<DataMember()>
Public stockAwards As IEnumerable(Of Single) = New Single(11) {}
<DataMember()>
Public otherPayments As Object = New ArrayList()
End Class
'required because List<object> is used polymorphically
'does not conflict with ArrayList above because it's a different scope,
'even though it's the same data contract
<DataContract(), KnownType(GetType(List(Of Object))),
KnownType(GetType(InHouseTraining)),
KnownType(GetType(OutsideTraining))>
Public Class Training
<DataMember()>
Public training As Object = New List(Of Object)()
End Class
<DataContract()>
Public Class InHouseTraining
'code omitted…
End Class
<DataContract()>
Public Class OutsideTraining
'code omitted…
End Class
Bei der Deserialisierung wird der deklarierte Typ unabhängig vom tatsächlich gesendeten Typ instanziiert, wenn der deklarierte Typ ein Sammlungstyp ist. Wenn der deklarierte Typ eine Sammlungsschnittstelle ist, wählt der Deserializer einen Typ aus, der ohne Bezug auf bekannte Typen instanziiert werden soll.
Außerdem wird bei der Deserialisierung, wenn der deklarierte Typ kein Sammlungstyp ist, aber ein Sammlungstyp gesendet wird, ein übereinstimmenden Sammlungstyp aus der Liste der bekannten Typen ausgewählt. Es ist möglich, der Liste bekannter Typen bei der Deserialisierung Sammlungsschnittstellentypen hinzuzufügen. In diesem Fall wählt die Deserialisierungs-Engine erneut einen Typ aus, der instanziiert werden soll.
Auflistungen und die NetDataContractSerializer-Klasse
Wenn die NetDataContractSerializer Klasse verwendet wird, verlieren nicht angepasste Auflistungstypen (ohne das CollectionDataContractAttribute Attribut), die keine Arrays sind, ihre besondere Bedeutung.
Nicht angepasste Sammlungstypen, die mit dem SerializableAttribute Attribut gekennzeichnet sind, können weiterhin von der NetDataContractSerializer Klasse gemäß dem SerializableAttribute Attribut oder den ISerializable Schnittstellenregeln serialisiert werden.
Benutzerdefinierte Sammlungstypen, Sammlungsschnittstellen und Arrays werden weiterhin als Sammlungen behandelt, auch wenn die NetDataContractSerializer Klasse verwendet wird.
Sammlungen und Schemata
Alle äquivalenten Auflistungen weisen die gleiche Darstellung im XML-Schema für die Schemadefinitionssprache (XSD) auf. Aus diesem Grund erhalten Sie normalerweise nicht dieselbe Sammlungsart im generierten Clientcode wie den auf dem Server. Der Server kann zum Beispiel einen Datenvertrag mit einem generischen List<T> Integer-Datenmitglied verwenden, aber im generierten Clientcode kann dasselbe Datenelement zu einem Array von Ganzzahlen werden.
Wörterbuchsammlungen werden mit einer WCF-spezifischen Schemaanmerkung gekennzeichnet, die darauf hinweist, dass sie Wörterbücher sind; andernfalls sind sie nicht von einfachen Listen zu unterscheiden, die Einträge mit einem Schlüssel und einem Wert enthalten. Eine genaue Beschreibung der Darstellung von Sammlungen im Datenvertragsschema finden Sie unter Data Contract Schema Reference.
Standardmäßig werden Typen für nicht angepasste Auflistungen im importierten Code nicht generiert. Datenmember von Listensammlungstypen werden als Arrays importiert, und Datenmember von Wörterbuchsammlungstypen werden als generisches Wörterbuch importiert.
Bei benutzerdefinierten Auflistungen werden jedoch separate Typen generiert, die mit dem CollectionDataContractAttribute Attribut gekennzeichnet sind. (Ein benutzerdefinierter Sammlungstyp im Schema ist ein Typ, der den Standardnamespace, den Namen, den wiederholten Elementnamen oder schlüssel/wert-Elementnamen nicht verwendet.) Diese Typen sind leere Typen, die von "Generic" List<T> für Listentypen und "Generic Dictionary" für Wörterbuchtypen abgeleitet werden.
Sie können z. B. die folgenden Typen auf dem Server haben.
[DataContract]
public class CountryOrRegion
{
[DataMember]
public Collection<string> officialLanguages;
[DataMember]
public List<DateTime> holidays;
[DataMember]
public CityList cities;
[DataMember]
public ArrayList otherInfo;
}
public class Person
{
public Person(string fName, string lName)
{
this.firstName = fName;
this.lastName = lName;
}
public string firstName;
public string lastName;
}
public class PeopleEnum : IEnumerator
{
public Person[] _people;
// Enumerators are positioned before the first element
// until the first MoveNext() call.
int position = -1;
public PeopleEnum(Person[] list)
{
_people = list;
}
public bool MoveNext()
{
position++;
return (position < _people.Length);
}
public void Reset()
{
position = -1;
}
public object Current
{
get
{
try
{
return _people[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
}
[CollectionDataContract(Name = "Cities", ItemName = "city", KeyName = "cityName", ValueName = "population")]
public class CityList : IDictionary<string, int>, IEnumerable<System.Collections.Generic.KeyValuePair<string, int>>
{
private Person[] _people = null;
public bool ContainsKey(string s) { return true; }
public bool Contains(string s) { return true; }
public bool Contains(KeyValuePair<string, int> item) { return (true); }
public void Add(string key, int value) { }
public void Add(KeyValuePair<string, int> keykValue) { }
public bool Remove(string s) { return true; }
public bool TryGetValue(string d, out int i)
{
i = 0; return (true);
}
/*
[TypeConverterAttribute(typeof(SynchronizationHandlesTypeConverter))]
public ICollection<string> SynchronizationHandles {
get { return (System.Collections.Generic.ICollection<string>) new Stack<string> (); }
set { }
}*/
public ICollection<string> Keys
{
get
{
return (System.Collections.Generic.ICollection<string>)new Stack<string>();
}
}
public int this[string s]
{
get
{
return 0;
}
set
{
}
}
public ICollection<int> Values
{
get
{
return (System.Collections.Generic.ICollection<int>)new Stack<string>();
}
}
public void Clear() { }
public void CopyTo(KeyValuePair<string, int>[] array, int index) { }
public bool Remove(KeyValuePair<string, int> item) { return true; }
public int Count { get { return 0; } }
public bool IsReadOnly { get { return true; } }
IEnumerator<KeyValuePair<string, int>>
System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, int>>.GetEnumerator()
{
return (IEnumerator<KeyValuePair<string, int>>)new PeopleEnum(_people); ;
}
public IEnumerator GetEnumerator()
{
return new PeopleEnum(_people);
}
}
<DataContract()>
Public Class CountryOrRegion
<DataMember()>
Public officialLanguages As Collection(Of String)
<DataMember()>
Public holidays As List(Of DateTime)
<DataMember()>
Public cities As CityList
<DataMember()>
Public otherInfo As ArrayList
End Class
Public Class Person
Public Sub New(ByVal fName As String, ByVal lName As String)
Me.firstName = fName
Me.lastName = lName
End Sub
Public firstName As String
Public lastName As String
End Class
Public Class PeopleEnum
Implements IEnumerator
Public _people() As Person
' Enumerators are positioned before the first element
' until the first MoveNext() call.
Private position As Integer = -1
Public Sub New(ByVal list() As Person)
_people = list
End Sub
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
position += 1
Return position < _people.Length
End Function
Public Sub Reset() Implements IEnumerator.Reset
position = -1
End Sub
Public ReadOnly Property Current() As Object Implements IEnumerator.Current
Get
Try
Return _people(position)
Catch e1 As IndexOutOfRangeException
Throw New InvalidOperationException()
End Try
End Get
End Property
End Class
<CollectionDataContract(Name:="Cities",
ItemName:="city",
KeyName:="cityName",
ValueName:="population")>
Public Class CityList
Implements IDictionary(Of String, Integer), IEnumerable(Of System.Collections.Generic.KeyValuePair(Of String, Integer))
Private _people() As Person = Nothing
Public Function ContainsKey(ByVal s As String) As Boolean Implements IDictionary(Of String, Integer).ContainsKey
Return True
End Function
Public Function Contains(ByVal s As String) As Boolean
Return True
End Function
Public Function Contains(ByVal item As KeyValuePair(Of String, Integer)) As Boolean Implements IDictionary(Of String, Integer).Contains
Return (True)
End Function
Public Sub Add(ByVal key As String,
ByVal value As Integer) Implements IDictionary(Of String, Integer).Add
End Sub
Public Sub Add(ByVal keykValue As KeyValuePair(Of String, Integer)) Implements IDictionary(Of String, Integer).Add
End Sub
Public Function Remove(ByVal s As String) As Boolean Implements IDictionary(Of String, Integer).Remove
Return True
End Function
Public Function TryGetValue(ByVal d As String,
<System.Runtime.InteropServices.Out()> ByRef i As Integer) _
As Boolean Implements IDictionary(Of String, Integer).TryGetValue
i = 0
Return (True)
End Function
Public ReadOnly Property Keys() As ICollection(Of String) Implements IDictionary(Of String, Integer).Keys
Get
Return CType(New Stack(Of String)(), System.Collections.Generic.ICollection(Of String))
End Get
End Property
Default Public Property Item(ByVal s As String) As Integer Implements IDictionary(Of String, Integer).Item
Get
Return 0
End Get
Set(ByVal value As Integer)
End Set
End Property
Public ReadOnly Property Values() As ICollection(Of Integer) Implements IDictionary(Of String, Integer).Values
Get
Return CType(New Stack(Of String)(), System.Collections.Generic.ICollection(Of Integer))
End Get
End Property
Public Sub Clear() Implements IDictionary(Of String, Integer).Clear
End Sub
Public Sub CopyTo(ByVal array() As KeyValuePair(Of String, Integer),
ByVal index As Integer) Implements IDictionary(Of String, Integer).CopyTo
End Sub
Public Function Remove(ByVal item As KeyValuePair(Of String, Integer)) As Boolean Implements IDictionary(Of String, Integer).Remove
Return True
End Function
Public ReadOnly Property Count() As Integer Implements IDictionary(Of String, Integer).Count
Get
Return 0
End Get
End Property
Public ReadOnly Property IsReadOnly() As Boolean Implements IDictionary(Of String, Integer).IsReadOnly
Get
Return True
End Get
End Property
Private Function IEnumerable_GetEnumerator() As IEnumerator(Of KeyValuePair(Of String, Integer)) _
Implements System.Collections.Generic.IEnumerable(Of System.Collections.Generic.KeyValuePair(Of String, Integer)).GetEnumerator
Return CType(New PeopleEnum(_people), IEnumerator(Of KeyValuePair(Of String, Integer)))
End Function
Public Function GetEnumerator() As IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return New PeopleEnum(_people)
End Function
End Class
Wenn das Schema erneut exportiert und wieder importiert wird, ähnelt der generierte Clientcode den folgenden (Felder werden anstelle von Eigenschaften zum einfacheren Lesen angezeigt).
[DataContract]
public class CountryOrRegion2
{
[DataMember]
public string[] officialLanguages;
[DataMember]
public DateTime[] holidays;
[DataMember]
public Cities cities;
[DataMember]
public object[] otherInfo;
}
[CollectionDataContract(ItemName = "city", KeyName = "cityName", ValueName = "population")]
public class Cities : Dictionary<string, int> { }
<DataContract()>
Public Class CountryOrRegion2
<DataMember()>
Public officialLanguages() As String
<DataMember()>
Public holidays() As DateTime
<DataMember()>
Public cities As Cities
<DataMember()>
Public otherInfo() As Object
End Class
<CollectionDataContract(ItemName:="city", KeyName:="cityName", ValueName:="population")>
Public Class Cities
Inherits Dictionary(Of String, Integer)
End Class
Möglicherweise möchten Sie unterschiedliche Typen im generierten Code als die Standardtypen verwenden. Sie können beispielsweise "Generic" BindingList<T> anstelle regulärer Arrays für Ihre Datenelemente verwenden, um die Bindung an Benutzeroberflächenkomponenten zu vereinfachen.
Um sammlungstypen auszuwählen, die generiert werden sollen, übergeben Sie eine Liste von Auflistungstypen, die Sie beim Importieren des Schemas in die ReferencedCollectionTypes Eigenschaft des ImportOptions Objekts verwenden möchten. Diese Typen werden als referenzierte Sammlungstypen bezeichnet.
Wenn auf generische Typen verwiesen wird, müssen sie entweder voll geöffnete Generika oder vollständig geschlossene Generika sein.
Hinweis
Bei Verwendung des tools Svcutil.exe kann dieser Verweis mithilfe des Befehlszeilenschalters /collectionType (kurz: /ct) erreicht werden. Denken Sie daran, dass Sie auch die Assembly für die referenzierten Sammlungstypen mithilfe des /reference-Schalters (Kurzform: /r) angeben müssen. Bei generischen Typen folgt auf den Namen des Typs ein Graviszeichen und die Anzahl der generischen Parameter. Verwechseln Sie das Graviszeichen (`) nicht mit dem einfachen Anführungszeichen (‘). Sie können mehrere Auflistungstypen angeben, auf die verwiesen wird, indem Sie den Schalter "/collectionType " mehrmals verwenden.
Um beispielsweise zu bewirken, dass alle Listen als generisch List<T>importiert werden.
svcutil.exe MyService.wsdl MyServiceSchema.xsd /r:C:\full_path_to_system_dll\System.dll /ct:System.Collections.Generic.List`1
Beim Importieren einer Auflistung wird diese Liste mit referenzierten Auflistungstypen überprüft, und die am besten übereinstimmende Auflistung wird verwendet, wenn eine gefunden wird, entweder als Datentyp (für nicht angepasste Auflistungen) oder als Basistyp, von dem abgeleitet werden soll (für benutzerdefinierte Auflistungen). Wörterbücher werden nur mit Wörterbüchern abgeglichen, während Listen mit Listen abgeglichen werden.
Wenn Sie z. B. "Generic" BindingList<T> und Hashtable der Liste der referenzierten Typen hinzufügen, ähnelt der generierte Clientcode für das vorangehende Beispiel folgendem.
[DataContract]
public class CountryOrRegion3
{
[DataMember]
public BindingList<string> officialLanguages;
[DataMember]
public BindingList<DateTime> holidays;
[DataMember]
public Cities cities;
[DataMember]
public BindingList<object> otherInfo;
}
[CollectionDataContract(ItemName = "city", KeyName = "cityName", ValueName = "population")]
public class Cities3 : Hashtable { }
<DataContract()>
Public Class CountryOrRegion3
<DataMember()>
Public officialLanguages As BindingList(Of String)
<DataMember()>
Public holidays As BindingList(Of DateTime)
<DataMember()>
Public cities As Cities
<DataMember()>
Public otherInfo As BindingList(Of Object)
End Class
<CollectionDataContract(ItemName:="city",
KeyName:="cityName",
ValueName:="population")>
Public Class Cities3
Inherits Hashtable
End Class
Sie können Sammlungsschnittstellentypen als Teil Der referenzierten Sammlungstypen angeben, aber Sie können keine ungültigen Sammlungstypen angeben (z. B. typen ohne Add Methode oder öffentlicher Konstruktor).
Ein geschlossener generischer Typ wird als beste Übereinstimmung betrachtet. (Nicht generische Typen gelten als gleichwertig mit geschlossenen Generika von Object). Wenn z. B. die Typen "Generic" List<T>, "Generic DateTimeBindingList<T> " (open generic) und ArrayList die referenzierten Sammlungstypen sind, wird Folgendes generiert.
[DataContract]
public class CountryOrRegion4
{
[DataMember]
public string[] officialLanguages;
[DataMember]
public DateTime[] holidays;
[DataMember]
public Cities cities;
[DataMember]
public object[] otherInfo;
}
[CollectionDataContract(ItemName = "city", KeyName = "cityName", ValueName = "population")]
public class Cities4 : Dictionary<string, int> { }
<DataContract()>
Public Class CountryOrRegion4
<DataMember()>
Public officialLanguages() As String
<DataMember()>
Public holidays() As DateTime
<DataMember()>
Public cities As Cities
<DataMember()>
Public otherInfo() As Object
End Class
<CollectionDataContract(ItemName:="city",
KeyName:="cityName",
ValueName:="population")>
Public Class Cities4
Inherits Dictionary(Of String, Integer)
End Class
Bei Listensammlungen werden nur die Fälle in der folgenden Tabelle unterstützt.
| Referenzierter Typ | Vom referenzierten Typ implementierte Schnittstelle | Beispiel | Typ behandelt als: |
|---|---|---|---|
| Nicht generische oder geschlossene generische (beliebige Anzahl von Parametern) | Nicht generisch | MyType : IListoder MyType<T> : IListwobei T= int |
Geschlossen generisch von Object (z. B. IList<object>) |
| Nicht generisch oder geschlossen (eine beliebige Anzahl von Parametern, die nicht unbedingt mit dem Sammlungstyp übereinstimmen) | Geschlossenes Generikum | MyType : IList<string>oder MyType<T> : IList<string> wobei T=int |
Geschlossen generisch (z. B. IList<string>) |
| Geschlossenes generisches Modell mit beliebiger Anzahl an Parametern | Offen generisch mit einem beliebigen Parameter des Typs | MyType<T,U,V> : IList<U>wobei T= int, U=string, V=bool |
Geschlossen generisch (z. B. IList<string>) |
| Offen generisch mit einem Parameter | Offen generisch mit dem Parameter des Typs |
MyType<T> : IList<T>, T ist geöffnet |
Offene generische (z. B. IList<T>) |
Wenn ein Typ mehrere Listensammlungsschnittstellen implementiert, gelten die folgenden Einschränkungen:
Wenn der Typ Generic-IEnumerable<T> (oder dessen abgeleitete Schnittstellen) mehrmals für unterschiedliche Typen implementiert, wird der Typ nicht als gültiger referenzierter Collection-Typ betrachtet und ignoriert. Dies gilt auch dann, wenn einige Implementierungen ungültig sind oder offene Generika verwenden. Beispielsweise würde ein Typ, der "Generic IEnumerable<T> von
int" und "Generic IEnumerable<T> von T" implementiert, niemals als referenzierte Sammlung vonintoder einem anderen Typ verwendet werden, unabhängig davon, ob der Typ eineAdd-Methode hat, dieintakzeptiert, oder eineAdd-Methode, die einen Parameter vom Typ T akzeptiert, oder beides.Wenn der Typ eine generische Sammlungsschnittstelle sowie IList implementiert, wird der Typ niemals als Referenzsammlungstyp verwendet, es sei denn, die generische Sammlungsschnittstelle ist ein geschlossener generischer Sammlungstyp wie bei Object.
Bei Wörterbuchsammlungen werden nur die Fälle in der folgenden Tabelle unterstützt.
| Referenzierter Typ | Vom referenzierten Typ implementierte Schnittstelle | Beispiel | Typ behandelt als |
|---|---|---|---|
| Nicht generische oder geschlossene generische (beliebige Anzahl von Parametern) | IDictionary | MyType : IDictionaryoder MyType<T> : IDictionary wobei T=int |
Geschlossenes generisches IDictionary<object,object> |
| Geschlossen generisch (beliebige Anzahl von Parametern) | IDictionary<TKey,TValue>, geschlossen |
MyType<T> : IDictionary<string, bool> wobei T=int |
Geschlossen generisch (z. B. IDictionary<string,bool>) |
| Geschlossen generisch (beliebige Anzahl von Parametern) | Generisches IDictionary<TKey,TValue>, entweder der Schlüssel oder der Wert ist geschlossen, das andere Element ist offen und verwendet einen Parameter des Typs |
MyType<T,U,V> : IDictionary<string,V> wobei T=int, U=float,V=booloder MyType<Z> : IDictionary<Z,bool> wobei Z=string |
Geschlossen generisch (z. B. IDictionary<string,bool>) |
| Geschlossen generisch (beliebige Anzahl von Parametern) | Generische IDictionary<TKey,TValue>, sowohl Schlüssel als auch Wert sind offen und verwenden jeweils einen der Parameter des Typs. |
MyType<T,U,V> : IDictionary<V,U> wobei T=int, U=bool, V=string |
Geschlossen generisch (z. B. IDictionary<string,bool>) |
| Offen allgemein (zwei Parameter) | Generic IDictionary<TKey,TValue>, Open, verwendet beide generischen Parameter des Typs in der Reihenfolge, in der sie erscheinen. |
MyType<K,V> : IDictionary<K,V>, K und V sind beide geöffnet |
Offene generische (z. B. IDictionary<K,V>) |
Wenn der Typ sowohl IDictionary als auch Generic IDictionary<TKey,TValue> implementiert, wird nur Generic IDictionary<TKey,TValue> berücksichtigt.
Das Verweisen auf partielle generische Typen wird nicht unterstützt.
Duplikate sind nicht zulässig. Beispielsweise können Sie nicht sowohl die generische List<T> von Integer als auch die generische Sammlung von IntegerReferencedCollectionTypeshinzufügen, da anschließend nicht mehr festgestellt werden kann, was verwendet werden soll, wenn eine Liste mit ganzen Zahlen im Schema auftritt. Duplikate werden nur erkannt, wenn es im Schema einen Typ gibt, der das Problem mit Duplikaten offenlegt. Wenn das zu importierende Schema keine Listen mit ganzen Zahlen enthält, ist es zulässig, sowohl die generische List<T> von Integer als auch die generische Sammlung von Integer im ReferencedCollectionTypes zu haben, aber keine von ihnen hat eine Auswirkung.
Erweiterte Sammlungsregeln
Serialisieren von Sammlungen
Es folgt eine Liste der Sammlungsregeln für die Serialisierung:
Das Kombinieren von Sammlungstypen (Sammlungen von Sammlungen) ist zulässig. Verzweigte Arrays werden als Sammlungen von Sammlungen behandelt. Mehrdimensionale Arrays werden nicht unterstützt.
Byte-Arrays und Arrays von XmlNode sind spezielle Arraytypen, die als primitive Datentypen behandelt werden, nicht als Auflistungen. Das Serialisieren eines Bytearrays führt zu einem einzelnen XML-Element, das einen Block von Base64-codierten Daten enthält, anstelle eines separaten Elements für jedes Byte. Weitere Informationen dazu, wie ein Array von XmlNode behandelt wird, finden Sie unter XML und ADO.NET Typen in Datenverträgen. Natürlich können diese besonderen Typen selbst Teil von Sammlungen sein: Ein Bytearray führt zu mehreren XML-Elementen, die jeweils einen Abschnitt aus Base64-codierten Daten enthalten.
Wenn das DataContractAttribute Attribut auf einen Sammlungstyp angewendet wird, wird der Typ als regulärer Datentyp behandelt, nicht als Sammlung.
Wenn ein Sammlungstyp die IXmlSerializable Schnittstelle implementiert, gelten die folgenden Regeln, je nach Typ
myType:IList<string>, IXmlSerializable:Wenn der deklarierte Typ lautet
IList<string>, wird der Typ als Liste serialisiert.Wenn der deklarierte Typ lautet
myType, wird er alsIXmlSerializableserialisiert.Wenn der deklarierte Typ lautet
IXmlSerializable, wird er serialisiert alsIXmlSerializable, aber nur, wenn Sie der Liste bekannter Typen hinzufügenmyType.
Auflistungen werden mithilfe der in der folgenden Tabelle gezeigten Methoden serialisiert und deserialisiert.
| Sammlungstyp implementiert | Methoden, die bei der Serialisierung aufgerufen werden | Bei der Deserialisierung aufgerufene Methode(n) |
|---|---|---|
| Generisches IDictionary<TKey,TValue> |
get_Keys, get_Values |
Generisches Hinzufügen |
| IDictionary |
get_Keys, get_Values |
Add |
| Generisches IList<T> | Generischer IList<T> Indexer | Generisches Hinzufügen |
| Generisches ICollection<T> | Aufzähler | Generisches Hinzufügen |
| IList | IList Indexerstellung | Add |
| Generisches IEnumerable<T> | GetEnumerator |
Eine nicht statische Methode namens Add, die einen Parameter des entsprechenden Typs nimmt (der Typ des generischen Parameters oder eines seiner Basistypen). Eine solche Methode muss für den Serialisierer vorhanden sein, um einen Sammlungstyp sowohl während der Serialisierung als auch der Deserialisierung als Sammlung zu behandeln. |
| IEnumerable (und daher ICollection, die sich daraus ableitet) | GetEnumerator |
Eine nicht-statische Methode namens Add, die einen Parameter vom Typ Object akzeptiert. Eine solche Methode muss für den Serialisierer vorhanden sein, um einen Sammlungstyp sowohl während der Serialisierung als auch der Deserialisierung als Sammlung zu behandeln. |
In der obigen Tabelle sind Auflistungsschnittstellen in absteigender Reihenfolge der Rangfolge aufgeführt. Dies bedeutet beispielsweise, dass, wenn ein Typ sowohl IList als auch Generic IEnumerable<T> implementiert, die Sammlung gemäß den IList-Regeln serialisiert und deserialisiert wird.
Bei der Deserialisierung werden alle Auflistungen deserialisiert, indem zuerst eine Instanz des Typs erstellt wird, indem der parameterlose Konstruktor aufgerufen wird, der für den Serialisierer vorhanden sein muss, um einen Sammlungstyp sowohl während der Serialisierung als auch während der Deserialisierung als Sammlung zu behandeln.
Wenn die gleiche generische Sammlungsschnittstelle mehrmals implementiert wird (z. B. wenn ein Typ sowohl Generic ICollection<T> von
Integerals auch Generic ICollection<T> von String implementiert) und keine Schnittstelle mit höherer Priorität gefunden wird, wird die Sammlung nicht als gültige Sammlung behandelt.Sammlungstypen können das SerializableAttribute Attribut auf sie angewendet haben und die ISerializable Schnittstelle implementieren. Beide werden ignoriert. Wenn der Typ jedoch nicht vollständig den Anforderungen des Sammlungstyps entspricht (z. B. fehlt die Methode), wird der
AddTyp nicht als Sammlungstyp betrachtet, und somit werden das SerializableAttribute Attribut und die ISerializable Schnittstelle verwendet, um zu bestimmen, ob der Typ serialisiert werden kann.Durch Anwenden des CollectionDataContractAttribute -Attributs auf eine Sammlung, um diese anzupassen, wird der oben genannte SerializableAttribute -Fallback-Mechanismus entfernt. Wenn eine benutzerdefinierte Auflistung die Anforderungen des Sammlungstyps nicht erfüllt, wird stattdessen eine InvalidDataContractException Ausnahme ausgelöst. Die Ausnahmezeichenfolge enthält häufig Informationen, die erläutern, warum ein bestimmter Typ nicht als gültige Auflistung betrachtet wird (keine
AddMethode, kein parameterloser Konstruktor usw.), daher ist es häufig nützlich, das CollectionDataContractAttribute Attribut für Debuggingzwecke anzuwenden.
Sammlungsbenennung
Hier ist eine Liste von Benennungsregeln für Sammlungen:
Der Standardnamespace für alle Datenverträge für Wörterbuchsammlungen sowie für Datenverträge für Listensammlungen, die primitive Typen enthalten, lautet
http://schemas.microsoft.com/2003/10/Serialization/Arrays, es sei denn, er wurde mit „Namespace“ überschrieben. Typen, die integrierten XSD-Typen zugeordnet sind, sowie die Typenchar,TimespanundGuidwerden zu diesem Zweck als Grundtypen betrachtet.Der Standardnamespace für Sammlungstypen, die nicht primitive Typen enthalten, sofern er nicht mithilfe von Namespace außer Kraft gesetzt wird, entspricht dem Datenvertragsnamespace des Typs, der in der Auflistung enthalten ist.
Der Standardname für Datenverträge für Sammlungstypen ist die Zeichenfolge "ArrayOf" in Kombination mit dem Datenvertragsnamen des in der Sammlung enthaltenen Typs, sofern er nicht von "Name" überschrieben wurde. Beispielsweise lautet der Datenvertragsname für eine generische Liste ganzzahliger Zahlen "ArrayOfint". Denken Sie daran, dass der Name des Datenvertrags
Object"anyType" lautet, sodass der Datenvertragsname nicht generischer Listen wie ArrayList "ArrayOfanyType" lautet.
Der Standardname für Datenverträge für Wörterbuchsammlungen ist die Zeichenfolge "ArrayOfKeyValueOf" in Kombination mit dem Datenvertragsnamen für den Schlüsseltyp, gefolgt vom Datenvertragsnamen des Werttyps, sofern er nicht von Nameüberschrieben wurde. Der Datenvertragsname für ein generisches Wörterbuch für Zeichenfolge und ganze Zahl lautet z. B. "ArrayOfKeyValueOfstringint". Wenn der Schlüssel oder die Werttypen nicht grundtypisch sind, wird außerdem ein Namespacehash der Datenvertragsnamespaces der Schlüssel- und Werttypen an den Namen angefügt. Weitere Informationen zu Namespacehashes finden Sie unter "Datenvertragsnamen".
Jeder Vertrag für Wörterbuchsammlungsdaten verfügt über einen Vertrag für Begleitdaten, der einen Eintrag im Wörterbuch darstellt. Der Name ist identisch mit dem Wörterbuchdatenvertrag, mit Ausnahme des Präfixes "ArrayOf", und der Namespace ist identisch mit dem Vertrag für Wörterbuchdaten. Beispielsweise kann für den "ArrayOfKeyValueOfstringint"-Wörterbuchdatenvertrag der "KeyValueofstringint"-Datenvertrag einen Eintrag im Wörterbuch darstellen. Sie können den Namen dieses Datenvertrags mithilfe der ItemName Eigenschaft anpassen, wie im nächsten Abschnitt beschrieben.
Allgemeine Benennungsregeln für Typs, wie unter "Datenvertragsnamen" beschrieben, gelten vollständig für Sammlungstypen; Das heißt, Sie können geschweifte Klammern innerhalb von Name verwenden, um generische Typparameter anzugeben. Zahlen innerhalb der geschweiften Klammern beziehen sich jedoch auf generische Parameter und nicht auf Typen, die in der Auflistung enthalten sind.
Sammlungsanpassung
Die folgenden Verwendungen des CollectionDataContractAttribute Attributs sind verboten und führen zu einer InvalidDataContractException Ausnahme:
Anwenden des DataContractAttribute Attributs auf einen Typ, auf den das CollectionDataContractAttribute Attribut angewendet wurde, oder auf einen der abgeleiteten Typen.
Anwenden des CollectionDataContractAttribute Attributs auf einen Typ, der die IXmlSerializable Schnittstelle implementiert.
Das Anwenden des CollectionDataContractAttribute -Attributs auf einen Typ, bei dem es sich nicht um einen Sammlungstyp handelt.
Der Versuch, KeyName oder ValueName auf einem CollectionDataContractAttribute -Attribut festzulegen, das auf einen Typ angewendet wird, bei dem es sich nicht um einen Wörterbuchtyp handelt.
Polymorphismusregeln
Wie bereits erwähnt, kann das Anpassen von Sammlungen mithilfe des CollectionDataContractAttribute Attributs die Austauschbarkeit der Sammlung beeinträchtigen. Zwei angepasste Auflistungstypen können nur dann als gleichwertig betrachtet werden, wenn name, Namespace, Elementname sowie Schlüssel- und Wertnamen übereinstimmen (wenn dies Wörterbuchsammlungen sind).
Aufgrund von Anpassungen kann es passieren, dass versehentlich ein Datenvertrag für Sammlungen verwendet wird, wenn ein anderer erwartet wird. Dies sollte vermieden werden. Sehen Sie sich die folgenden Typen an.
[DataContract]
public class Student
{
[DataMember]
public string name;
[DataMember]
public IList<int> testMarks;
}
public class Marks1 : List<int> {}
[CollectionDataContract(ItemName="mark")]
public class Marks2 : List<int> {}
<DataContract()>
Public Class Student
<DataMember()>
Public name As String
<DataMember()>
Public testMarks As IList(Of Integer)
End Class
Public Class Marks1
Inherits List(Of Integer)
End Class
<CollectionDataContract(ItemName:="mark")>
Public Class Marks2
Inherits List(Of Integer)
End Class
In diesem Fall kann eine Instanz von Marks1testMarkszugewiesen werden.
Marks2 sollte jedoch nicht verwendet werden, da sein Datenvertrag nicht als gleichwertig mit dem IList<int> Datenvertrag angesehen wird. Der Datenvertragsname ist "Marks2" und nicht "ArrayOfint", und der Name des wiederholten Elements ist "<mark>" und nicht "<int>".
Die Regeln in der folgenden Tabelle gelten für die polymorphe Zuordnung von Auflistungen.
| Deklarierter Typ | Zuweisen einer nicht benutzerdefinierten Sammlung | Zuweisen einer benutzerdefinierten Sammlung |
|---|---|---|
| Objekt | Vertragsname wird serialisiert. | Vertragsname wird serialisiert. Anpassungen werden vorgenommen. |
| Schnittstelle für Sammlungen | Vertragsname wird nicht serialisiert. | Vertragsname wird nicht serialisiert. Anpassung wird nicht verwendet.* |
| Nicht personalisierte Sammlung | Vertragsname wird nicht serialisiert. | Vertragsname wird serialisiert. Anpassung wird verwendet.** |
| Angepasste Sammlung | Vertragsname wird serialisiert. Anpassung wird nicht verwendet.** | Vertragsname wird serialisiert. Anpassung des zugewiesenen Typs wird verwendet. ** |
In diesem Fall erfolgt die Anpassung über die NetDataContractSerializer Klasse. Die NetDataContractSerializer Klasse serialisiert auch den tatsächlichen Typnamen in diesem Fall, sodass die Deserialisierung wie erwartet funktioniert.
** Diese Fälle führen zu Instanzen, die dem Schema nach ungültig sind und somit vermieden werden sollten.
In den Fällen, in denen der Vertragsname serialisiert wird, sollte der zugewiesene Sammlungstyp in der Liste der bekannten Typen enthalten sein. Das Gegenteil ist auch wahr: In den Fällen, in denen der Name nicht serialisiert wird, ist das Hinzufügen des Typs zur Liste bekannter Typen nicht erforderlich.
Ein Array eines abgeleiteten Typs kann einem Array eines Basistyps zugewiesen werden. In diesem Fall wird der Vertragsname für den abgeleiteten Typ für jedes wiederholte Element serialisiert. Wenn z. B. ein Typ Book vom Typ LibraryItemabgeleitet ist, können Sie einem Array von Book einem Array von LibraryItemzuweisen. Dies gilt nicht für andere Sammlungstypen. Sie können z. B. eine Generic List of Book nicht einem Generic List of LibraryItemzuweisen. Sie können jedoch ein Generic List of LibraryItem zuweisen, das Book Instanzen enthält. Sowohl im Array-Fall als auch im Nicht-Array-Fall sollte Book in der Liste der bekannten Typen enthalten sein.
Erhaltung von Sammlungen und Objektreferenzen
Wenn ein Serialisierer in einem Modus funktioniert, in dem Objektverweise beibehalten werden, gilt die Objektreferenzerhaltung auch für Auflistungen. Insbesondere wird die Objektidentität sowohl für ganze Sammlungen als auch für einzelne Elemente, die in Sammlungen enthalten sind, beibehalten. Bei Wörterbüchern wird die Objektidentität sowohl für die Schlüssel-Wert-Paarobjekte als auch für die einzelnen Schlüssel- und Wertobjekte beibehalten.