Megosztás a következőn keresztül:


Adatgyűjtési típusok az adatszerződésekben

A gyűjtemény egy bizonyos típusú elemek listája. A .NET-keretrendszer az ilyen listák tömbökkel vagy számos más típussal (Általános lista, Általános BindingList<T>StringCollectionvagy ArrayList). Előfordulhat például, hogy egy gyűjtemény egy adott ügyfél címlistáját tartalmazza. Ezeket a gyűjteményeket listagyűjteményeknek nevezzük, a tényleges típusuktól függetlenül.

Létezik egy speciális gyűjteményforma, amely az egyik elem (a "kulcs") és a másik (az "érték") közötti társításokat jelöli. A .NET-keretrendszer ezeket olyan típusok jelölik, mint például Hashtable az általános szótár. Egy társításgyűjtemény például leképezhet egy várost ("kulcsot") a lakosságához ("érték"). Ezeket a gyűjteményeket szótárgyűjteményeknek nevezzük, a tényleges típusuktól függetlenül.

A gyűjtemények különleges bánásmódban részesülnek az adatszerződési modellben.

Az interfészt megvalósító típusok, beleértve a IEnumerable tömböket és az általános gyűjteményeket, gyűjteményként lesznek felismerve. Ezek közül az általános IDictionary<TKey,TValue> vagy általános IDictionary felületeket megvalósító típusok szótárgyűjtemények, a többi listagyűjtemény.

A gyűjteménytípusokra vonatkozó további követelményeket, például egy metódus meghívását Add és egy paraméter nélküli konstruktort a következő szakaszok ismertetik részletesen. Ez biztosítja, hogy a gyűjteménytípusok szerializálhatók és deszerializálhatók legyenek. Ez azt jelenti, hogy egyes gyűjtemények nem támogatottak közvetlenül, például az Általános ReadOnlyCollection<T> (mivel nincs paraméter nélküli konstruktor). A korlátozások megkerülésével kapcsolatos információkért lásd a jelen témakör későbbi, "A gyűjtemény felülettípusainak és írásvédett gyűjteményeinek használata" című szakaszát.

A gyűjteményekben található típusok adatszerződés-típusok, vagy egyéb módon szerializálhatók. További információ: Adatszerződés szerializáló által támogatott típusok.

A gyűjtemények szerializálásával kapcsolatos további információkért tekintse meg a témakör "Speciális gyűjteményszabályok" című szakaszának gyűjteményeinek szerializálásával kapcsolatos információkat.

Felcserélhető gyűjtemények

Az azonos típusú listagyűjtemények mindegyike ugyanazzal az adatszerződéssel rendelkezik (kivéve, ha az CollectionDataContractAttribute attribútum használatával vannak testre szabva, ahogyan azt a jelen témakör későbbi részében tárgyaltuk). Így például a következő adatszerződések egyenértékűek.

[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

Mindkét adatszerződés az alábbi kódhoz hasonló XML-t eredményez.

<PurchaseOrder>
    <customerName>...</customerName>
    <items>
        <Item>...</Item>
        <Item>...</Item>
        <Item>...</Item>
        ...
    </items>
    <comments>
        <string>...</string>
        <string>...</string>
        <string>...</string>
        ...
    </comments>
</PurchaseOrder>

A gyűjtemények felcserélhetősége lehetővé teszi például a kiszolgáló teljesítményére optimalizált gyűjteménytípus és az ügyfél felhasználói felületének összetevőihez kötött gyűjteménytípus használatát.

A listagyűjteményekhez hasonlóan az azonos kulcs- és értéktípusú szótárgyűjtemények is azonos adatszerződéssel rendelkeznek (hacsak az attribútum nem szabja testre).CollectionDataContractAttribute

Csak az adatszerződés típusa számít a gyűjtési egyenértékűség szempontjából, a .NET-típusok nem. Vagyis az 1. típusú gyűjtemény egyenértékűnek minősül a 2. típusú gyűjteménysel, ha az 1. és a 2. típus egyenértékű adatszerződéssel rendelkezik.

A nem általános gyűjtemények adatszerződése megegyezik az általános típusú Objectgyűjteményekkel. (Például az adatszerződések ArrayList és az általános List<T> szerződések Object azonosak.)

Gyűjteményi felülettípusok és írásvédett gyűjtemények használata

A gyűjtőfelület-típusok (IEnumerable, általános IDictionaryIDictionary<TKey,TValue>vagy ezekből a felületekből származtatott felületek) szintén gyűjtésiadat-szerződésekkel rendelkeznek, amelyek egyenértékűek a tényleges gyűjteménytípusok gyűjtési adatszerződésével. Így deklarálható, hogy a szerializált típus gyűjteményfelület-típus, és az eredmények megegyeznek azzal, mintha tényleges gyűjteménytípust használtak volna. A következő adatszerződések például egyenértékűek.

[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

A szerializálás során, ha a deklarált típus egy interfész, akkor a tényleges példánytípus bármilyen típusú lehet, amely megvalósítja ezt a felületet. A korábban tárgyalt korlátozások (paraméter nélküli konstruktor és Add metódus) nem érvényesek. A Customer2-ben például beállíthatja a címeket általános ReadOnlyCollection<T> címpéldányra, annak ellenére, hogy nem deklarálhat közvetlenül általános ReadOnlyCollection<T>típusú adattagot.

A deszerializálás során, amikor a deklarált típus egy interfész, a szerializálási motor kiválaszt egy típust, amely implementálja a deklarált felületet, és a típus példányosítva lesz. Az ismert típusok mechanizmusa (az adatszerződés ismert típusaiban leírt) itt nincs hatással; a típus kiválasztása a WCF-be van beépítve.

Gyűjteménytípusok testreszabása

A gyűjteménytípusok testre szabhatók az CollectionDataContractAttribute attribútummal, amelynek több felhasználási módja is van.

Vegye figyelembe, hogy a gyűjteménytípusok testreszabása rontja a gyűjtemények felcserélhetőségét, ezért általában ajánlott elkerülni az attribútum alkalmazását, amikor csak lehetséges. A problémával kapcsolatos további információkért tekintse meg a témakör későbbi, "Speciális gyűjteményszabályok" című szakaszát.

Adatgyűjtési szerződés elnevezése

Az elnevezési gyűjteménytípusok szabályai hasonlóak a normál adatszerződés-típusok elnevezésére vonatkozó szabályokhoz, az adatszerződések neveiben leírtak szerint, bár vannak néhány fontos különbség:

  • Az CollectionDataContractAttribute attribútum az attribútum helyett a név testreszabására DataContractAttribute szolgál. Az CollectionDataContractAttribute attribútum rendelkezik és Namespace tulajdonságokkal is rendelkezikName.

  • Ha az CollectionDataContractAttribute attribútum nincs alkalmazva, a gyűjteménytípusok alapértelmezett neve és névtere a gyűjteményben található típusok nevétől és névterétől függ. A gyűjteménytípus neve és névtere nem befolyásolja őket. Példaként tekintse meg a következő típusokat.

    public CustomerList1 : Collection<string> {}
    public StringList1 : Collection<string> {}
    

Mindkét típus adatszerződésének neve "ArrayOfstring" és nem "CustomerList1" vagy "StringList1". Ez azt jelenti, hogy az ilyen típusok gyökérszintű szerializálása az alábbi kódhoz hasonló XML-t eredményez.

<ArrayOfstring>
    <string>...</string>
    <string>...</string>
    <string>...</string>
    ...
</ArrayOfstring>

Ez az elnevezési szabály lett kiválasztva annak biztosítására, hogy a sztringlistát képviselő nem testre szabott típusok azonos adatszerződéssel és XML-reprezentációval rendelkezzenek. Ez lehetővé teszi a gyűjtemények felcserélhetőségét. Ebben a példában a CustomerList1 és a StringList1 teljesen felcserélhető.

Az attribútum alkalmazásakor CollectionDataContractAttribute azonban a gyűjtemény testre szabott adatgyűjtési adatszerződéssé válik, még akkor is, ha az attribútumon nincs beállítva tulajdonság. A gyűjtési adatszerződés neve és névtere ezután magától a gyűjteménytípustól függ. Példaként tekintse meg a következő típust.

[CollectionDataContract]
public class CustomerList2 : Collection<string> {}
<CollectionDataContract()>
Public Class CustomerList2
    Inherits Collection(Of String)
End Class

Szerializáláskor az eredményként kapott XML az alábbihoz hasonló.

<CustomerList2>
    <string>...</string>
    <string>...</string>
    <string>...</string>
    ...
</CustomerList2>

Figyelje meg, hogy ez már nem felel meg a nem testre szabott típusok XML-reprezentációjának.

  • Az elnevezés további testreszabásához használhatja a Name tulajdonságokat és Namespace a tulajdonságokat. Lásd az alábbi osztályt.

    [CollectionDataContract(Name="cust_list")]
    public class CustomerList3 : Collection<string> {}
    
    <CollectionDataContract(Name:="cust_list")>
    Public Class CustomerList3
        Inherits Collection(Of String)
    End Class
    

Az eredményként kapott XML a következőhöz hasonló.

<cust_list>
    <string>...</string>
    <string>...</string>
    <string>...</string>
    ...
</cust_list>

További információkért tekintse meg a témakör későbbi részében található "Speciális gyűjteményszabályok" című szakaszt.

Az ismétlődő elem nevének testreszabása a listagyűjteményekben

A listagyűjtemények ismétlődő bejegyzéseket tartalmaznak. Általában minden ismétlődő bejegyzés a gyűjteményben található típus adatszerződésének neve alapján elnevezett elemként jelenik meg.

CustomerList A példákban a gyűjtemények sztringeket tartalmaztak. A sztring primitív típus adatszerződésének neve "sztring", ezért az ismétlődő elem "<sztring>" volt.

Az attribútum tulajdonságának ItemName használatával azonban ez az CollectionDataContractAttribute ismétlődő elemnév testre szabható. Példaként tekintse meg a következő típust.

[CollectionDataContract(ItemName="customer")]
public class CustomerList4 : Collection<string>  {}
<CollectionDataContract(ItemName:="customer")>
Public Class CustomerList4
    Inherits Collection(Of String)
End Class

Az eredményként kapott XML a következőhöz hasonló.

<CustomerList4>
    <customer>...</customer>
    <customer>...</customer>
    <customer>...</customer>
    ...
</CustomerList4>

Az ismétlődő elem névtere mindig megegyezik a gyűjtési adatszerződés névterével, amely a Namespace tulajdonság használatával testre szabható, a korábban leírtak szerint.

Szótárgyűjtemények testreszabása

A szótárgyűjtemények lényegében bejegyzések listájai, ahol minden bejegyzéshez tartozik egy kulcs, amelyet egy érték követ. A normál listákhoz hasonlóan a tulajdonság használatával ItemName is módosíthatja az ismétlődő elemnek megfelelő elemnevet.

Emellett módosíthatja a kulcsot és az értéket képviselő elemneveket a tulajdonságok és ValueName a KeyName tulajdonságok használatával. Ezeknek az elemeknek a névterei megegyeznek a gyűjtési adatszerződés névterével.

Példaként tekintse meg a következő típust.

[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

Szerializáláskor az eredményként kapott XML az alábbihoz hasonló.

<CountriesOrRegionsWithCapitals>
    <entry>
        <countryorregion>USA</countryorregion>
        <capital>Washington</capital>
    </entry>
    <entry>
        <countryorregion>France</countryorregion>
        <capital>Paris</capital>
    </entry>
    ...
</CountriesOrRegionsWithCapitals>

A szótárgyűjteményekkel kapcsolatos további információkért tekintse meg a témakör későbbi, "Speciális gyűjteményi szabályok" szakaszát.

Gyűjtemények és ismert típusok

Nem kell gyűjteménytípusokat hozzáadnia az ismert típusokhoz, ha más gyűjtemények vagy gyűjteményi felületek helyett polimorfikusan használják. Ha például egy típusú IEnumerable adattagot deklarál, és a példány ArrayListelküldéséhez használja, akkor nem kell hozzáadnia ArrayList az ismert típusokhoz.

Ha nem gyűjteménytípusok helyett polimorfikus gyűjteményeket használ, azokat ismert típusokhoz kell hozzáadni. Ha például egy típusú Object adattagot deklarál, és a használatával elküldi a példányt ArrayList, adja hozzá ArrayList az ismert típusokhoz.

Ez nem teszi lehetővé az egyenértékű gyűjtemények polimorfikus szerializálását. Ha például ArrayList hozzáadja az előző példában szereplő ismert típusokat tartalmazó listához, ez nem teszi lehetővé az Array of Object osztály hozzárendelését, még akkor sem, ha az azonos adatszerződéssel rendelkezik. Ez nem különbözik a nem gyűjteménytípusok szerializálásának szokásos ismert típusaitól, de különösen fontos megérteni a gyűjtemények esetében, mert nagyon gyakori, hogy a gyűjtemények egyenértékűek legyenek.

A szerializálás során csak egy típus ismerhető egy adott adatszerződés adott hatókörében, és az ezzel egyenértékű gyűjtemények mindegyike ugyanazzal az adatszerződéssel rendelkezik. Ez azt jelenti, hogy az előző példában nem adhat hozzá mindkettőt ArrayList és Array of Object ismert típusokat ugyanabban a hatókörben. Ez szintén egyenértékű a nem gyűjteménytípusok ismert típusaival, de különösen fontos megérteni a gyűjtemények esetében.

A gyűjtemények tartalmához ismert típusok is szükségesek lehetnek. Ha például egy ArrayList ténylegesen tartalmaz példányokat Type1 és Type2, mindkét típust hozzá kell adni az ismert típusokhoz.

Az alábbi példa egy megfelelően összeállított objektumgráfot mutat be gyűjtemények és ismert típusok használatával. A példa kissé ellentmondásos, mert egy tényleges alkalmazásban általában nem definiálná a következő adattagokat Object, és így nincsenek ismert típus-/polimorfizmusi problémák.

[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

Deszerializáláskor, ha a deklarált típus gyűjteménytípus, a rendszer a deklarált típust a ténylegesen elküldött típustól függetlenül példányosít. Ha a deklarált típus gyűjtőfelület, a deszerializáló kiválaszt egy példányosítandó típust az ismert típusok nélkül.

A deszerializáláskor is, ha a deklarált típus nem gyűjteménytípus, hanem gyűjteménytípus, akkor a rendszer kiválaszt egy megfelelő gyűjteménytípust az ismert típusok listájából. A deszerializálás ismert típusainak listájához gyűjtési felülettípusokat is hozzáadhat. Ebben az esetben a deszerializálási motor ismét kiválaszt egy példányosítandó típust.

Gyűjtemények és a NetDataContractSerializer osztály

Ha az osztály használatban van, a NetDataContractSerializer nem testreszabott gyűjteménytípusok (attribútum CollectionDataContractAttribute nélkül), amelyek nem tömbök, elveszítik különleges jelentésüket.

Az attribútummal SerializableAttribute megjelölt nem testre szabott gyűjteménytípusok továbbra is szerializálhatók az NetDataContractSerializer osztály által az attribútum vagy a SerializableAttributeISerializable felület szabályai szerint.

A testre szabott gyűjteménytípusok, gyűjteményillesztők és tömbök továbbra is gyűjteményként lesznek kezelve, még akkor is, ha az NetDataContractSerializer osztály használatban van.

Gyűjtemények és séma

Minden ezzel egyenértékű gyűjteménynek ugyanaz a reprezentációja az XML-sémadefiníciós (XSD) sémában. Emiatt általában nem ugyanaz a gyűjteménytípus jelenik meg a létrehozott ügyfélkódban, mint a kiszolgálón. Előfordulhat például, hogy a kiszolgáló adatszerződést használ egy Általános List<T> egész adattaggal, de a generált ügyfélkódban ugyanaz az adattag egész számok tömbje lehet.

A szótárgyűjtemények WCF-specifikus sémajegyzetekkel vannak megjelölve, amelyek azt jelzik, hogy szótárak; ellenkező esetben megkülönböztethetetlenek az olyan egyszerű listákból, amelyek kulcssal és értékkel rendelkező bejegyzéseket tartalmaznak. A gyűjtemények adatszerződéssémában való ábrázolásának pontos leírását az Adatszerződés sémahivatkozása című témakörben talál.

Alapértelmezés szerint a rendszer nem hoz létre típusokat nem testreszabott gyűjteményekhez az importált kódban. A listagyűjtemény-típusok adattagjait tömbökként importálja a rendszer, a szótárcsoport-típusok adattagjait pedig általános szótárként importálja a rendszer.

A testreszabott gyűjtemények esetében azonban külön típusok jönnek létre, és az CollectionDataContractAttribute attribútummal vannak megjelölve. (A sémában a testre szabott gyűjteménytípus nem használja az alapértelmezett névteret, nevet, ismétlődő elemnevet vagy kulcs/érték elem nevét.) Ezek a típusok üres típusok, amelyek a listatípusok általános List<T> és a szótártípusok általános szótárából származnak.

Előfordulhat például, hogy a kiszolgálón a következő típusok vannak.

[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

A séma exportálása és újbóli importálása után a létrehozott ügyfélkód a következőhöz hasonló (a tulajdonságok helyett mezők jelennek meg az olvasás megkönnyítése érdekében).

[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

Előfordulhat, hogy a létrehozott kódban más típusokat szeretne használni, mint az alapértelmezetteket. Előfordulhat például, hogy a szokásos tömbök helyett általános BindingList<T> tömböket szeretne használni az adattagok számára, hogy könnyebben kösse őket a felhasználói felület összetevőihez.

A létrehozandó gyűjteménytípusok kiválasztásához adja át az objektum tulajdonságába a ReferencedCollectionTypes séma importálása ImportOptions során használni kívánt gyűjteménytípusok listáját. Ezeket a típusokat hivatkozott gyűjteménytípusoknak nevezzük.

Általános típusokra való hivatkozáskor vagy teljesen nyitott vagy teljesen zárt generikus típusoknak kell lenniük.

Feljegyzés

A Svcutil.exe eszköz használatakor ez a hivatkozás a /collectionType parancssori kapcsolóval (rövid űrlap: /ct) végezhető el. Ne feledje, hogy a hivatkozott gyűjteménytípusok szerelvényét is meg kell adnia a /reference kapcsolóval (rövid űrlap: /r). Ha a típus általános, akkor azt egy visszajegyzésnek és az általános paraméterek számának kell követnie. A hátsó idézőjelet (') nem szabad összekeverni az egyetlen idézőjel (') karakterrel. A /collectionType kapcsoló többszöri használatával több hivatkozott gyűjteménytípust is megadhat.

Például az összes lista általánosként List<T>való importálását okozhatja.

svcutil.exe MyService.wsdl MyServiceSchema.xsd /r:C:\full_path_to_system_dll\System.dll /ct:System.Collections.Generic.List`1

Bármely gyűjtemény importálásakor a rendszer beolvasja a hivatkozott gyűjteménytípusok listáját, és a legjobban megfeleltethető gyűjteményt használja a rendszer, ha van ilyen, akár adattagtípusként (nem testreszabott gyűjtemények esetén), akár alaptípusként (testreszabott gyűjtemények esetén). A szótárak csak a szótárakhoz vannak egyeztetve, míg a listák a listákhoz vannak egyeztetve.

Ha például hozzáadja az Általános BindingList<T> és Hashtable a hivatkozott típusok listáját, az előző példához létrehozott ügyfélkód az alábbihoz hasonló.

[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

A hivatkozott gyűjteménytípusok részeként megadhatja a gyűjtemény felülettípusait, de érvénytelen gyűjteménytípusokat (például metódus nélküli vagy nyilvános konstruktort Add ) nem adhat meg.

A zárt generikus a legjobb egyezés. (A nem általános típusok egyenértékűnek tekinthetők a zárt generikusokkal Object. Ha például az Általános List<T>DateTime(open generic) típusú, BindingList<T> és ArrayList a hivatkozott gyűjteménytípusok, a következő jön létre.

[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

Listagyűjtemények esetén csak az alábbi táblázatban szereplő esetek támogatottak.

Hivatkozott típus Hivatkozott típus által implementált felület Példa A következőként kezelt típus:
Nem általános vagy zárt generikus (tetszőleges számú paraméter) Nem általános MyType : IList

vagy

MyType<T> : IList

ahol T= int
Zárt általános ( Object például IList<object>)
Nem általános vagy zárt generikus (olyan paraméterek száma, amelyek nem feltétlenül egyeznek a gyűjtemény típusával) Zárt általános MyType : IList<string>

vagy

MyType<T> : IList<string> ahol T=int
Zárt általános (például IList<string>)
Zárt általános, tetszőleges számú paraméterrel Nyissa meg az általánost a típus bármelyik paraméterével MyType<T,U,V> : IList<U>

ahol T=int, U=string, V=bool
Zárt általános (például IList<string>)
Általános megnyitás egy paraméterrel Általános megnyitás a típus paraméterével MyType<T> : IList<T>, T nyitva van Általános megnyitás (például IList<T>)

Ha egy típus egynél több listagyűjteményi felületet implementál, a következő korlátozások érvényesek:

  • Ha a típus többször implementálja az Általános IEnumerable<T> (vagy annak származtatott felületeit) különböző típusok esetében, a típus nem tekinthető érvényes hivatkozott gyűjteménytípusnak, és figyelmen kívül hagyja. Ez akkor is igaz, ha egyes implementációk érvénytelenek, vagy nyílt általános generikusokat használnak. A T általános és int általános IEnumerable<T>IEnumerable<T> értékét implementáló típus például soha nem használható hivatkozási gyűjteményként int vagy más típusként, függetlenül attól, hogy a típus rendelkezik-e Add metódust elfogadó intAdd vagy T típusú paramétert elfogadó metódussal, vagy mindkettővel.

  • Ha a típus általános gyűjteményfelületet is IListimplementál, akkor a rendszer soha nem használja a típust hivatkozott gyűjteménytípusként, kivéve, ha az általános gyűjtemény felülete egy zárt generikus típus Object.

Szótárgyűjtemények esetén csak az alábbi táblázatban szereplő esetek támogatottak.

Hivatkozott típus Hivatkozott típus által implementált felület Példa A kezelt típus
Nem általános vagy zárt generikus (tetszőleges számú paraméter) IDictionary MyType : IDictionary

vagy

MyType<T> : IDictionary ahol T=int
Zárt általános IDictionary<object,object>
Zárt általános (tetszőleges számú paraméter) IDictionary<TKey,TValue>Zárt MyType<T> : IDictionary<string, bool> ahol T=int Zárt általános (például IDictionary<string,bool>)
Zárt általános (tetszőleges számú paraméter) Általános IDictionary<TKey,TValue>, az egyik kulcs vagy érték bezárva van, a másik nyitott, és a típus egyik paraméterét használja MyType<T,U,V> : IDictionary<string,V> ahol T=int, U=float,V=bool

vagy

MyType<Z> : IDictionary<Z,bool> ahol Z=string
Zárt általános (például IDictionary<string,bool>)
Zárt általános (tetszőleges számú paraméter) Általános IDictionary<TKey,TValue>, a kulcs és az érték is nyitva van, és mindegyik a típus egyik paraméterét használja MyType<T,U,V> : IDictionary<V,U> ahol T=int, U=bool, V=string Zárt általános (például IDictionary<string,bool>)
Általános megnyitás (két paraméter) Az általános IDictionary<TKey,TValue>, nyitott, a típus mindkét általános paraméterét a megjelenő sorrendben használja MyType<K,V> : IDictionary<K,V>, K és V egyaránt nyitva Általános megnyitás (például IDictionary<K,V>)

Ha a típus mindkét típust implementálja, és az Általános IDictionary<TKey,TValue>típust isIDictionary, akkor csak a Generic IDictionary<TKey,TValue> lesz figyelembe véve.

A részleges általános típusok hivatkozása nem támogatott.

Az ismétlődések nem engedélyezettek, például nem lehet hozzáadni az általános List<T>Integer és az általános gyűjteményt IntegerReferencedCollectionTypesis, mert így lehetetlen meghatározni, hogy melyik legyen használva, ha az egész számok listája megtalálható a sémában. A rendszer csak akkor észleli az ismétlődéseket, ha a sémában olyan típus található, amely az ismétlődések problémáját teszi elérhetővé. Ha például az importált séma nem tartalmazza az egész számok listáját, akkor az általános és az általános gyűjtemény Integer is szerepelhet List<T>Integer a ReferencedCollectionTypesfájlban, de egyiknek sincs hatása.

Speciális gyűjteményszabályok

Gyűjtemények szerializálása

A szerializálás gyűjtési szabályainak listája a következő:

  • A gyűjteménytípusok (gyűjteménygyűjteményekkel) kombinálása engedélyezett. A szaggatott tömbök gyűjteményként vannak kezelve. A többdimenziós tömbök nem támogatottak.

  • A bájtok és tömbök tömbjei XmlNode olyan speciális tömbtípusok, amelyek primitívként, nem gyűjteményként vannak kezelve. A bájttömb szerializálása egyetlen XML-elemet eredményez, amely a Base64 kódolású adatok egy részét tartalmazza az egyes bájtok külön eleme helyett. További információ a tömbök kezeléséről XmlNode : XML és ADO.NET Adatszerződések típusai. Természetesen ezek a speciális típusok maguk is részt vehetnek a gyűjteményekben: a bájttömbök tömbje több XML-elemet eredményez, amelyek mindegyike Base64-kódolású adatokat tartalmaz.

  • Ha az DataContractAttribute attribútum egy gyűjteménytípusra van alkalmazva, a rendszer nem gyűjteményként, hanem normál adatszerződés-típusként kezeli a típust.

  • Ha egy gyűjteménytípus implementálja az IXmlSerializable interfészt, a következő szabályok vonatkoznak egy típusra myType:IList<string>, IXmlSerializable:

    • Ha a deklarált típus az IList<string>, a típus listaként szerializálva lesz.

    • Ha a deklarált típus az myType, akkor szerializálva IXmlSerializablelesz .

    • Ha a deklarált típus az IXmlSerializable, akkor szerializálva IXmlSerializablevan, de csak akkor, ha hozzáadja myType az ismert típusok listájához.

  • A gyűjtemények szerializálása és deszerializálása az alábbi táblázatban látható módszerekkel történik.

Gyűjteménytípus implementálása Szerializálásra hívott metódus(ok) Deszerializálásra hívott metódus(ok)
Általános IDictionary<TKey,TValue> get_Keys, get_Values Általános hozzáadás
IDictionary get_Keys, get_Values Add
Általános IList<T> Általános IList<T> indexelő Általános hozzáadás
Általános ICollection<T> Enumerátor Általános hozzáadás
IList IList Indexelő Add
Általános IEnumerable<T> GetEnumerator Egy nem statikus metódus, Add amely a megfelelő típus egyik paraméterét (az általános paraméter típusát vagy az egyik alaptípusát) veszi igénybe. Ilyen módszernek kell lennie ahhoz, hogy a szerializáló gyűjteményként kezelje a gyűjteménytípust a szerializálás és a deszerializálás során.
IEnumerable (és így ICollection, amely abból származik) GetEnumerator Egy nem statikus metódus, amely Add egy típusú Objectparamétert használ. Ilyen módszernek kell lennie ahhoz, hogy a szerializáló gyűjteményként kezelje a gyűjteménytípust a szerializálás és a deszerializálás során.

Az előző táblázat csökkenő sorrendben sorolja fel a gyűjtemény felületeit. Ez azt jelenti például, hogy ha egy típus mind az Általános, mind IList az Általános IEnumerable<T>típust implementálja, a gyűjtemény szerializálva és deszerializálva lesz a IList szabályok szerint:

  • A deszerializáláskor a rendszer az összes gyűjteményt deszerializálja. Ehhez először létre kell hoznia egy ilyen típusú példányt a paraméter nélküli konstruktor meghívásával, amelynek jelen kell lennie ahhoz, hogy a szerializáló gyűjteményként kezelje a gyűjteménytípust a szerializálás és a deszerializálás során.

  • Ha ugyanazt az általános gyűjteményfelületet többször implementálja (például ha egy típus a Generic ICollection<T> of és az Generic ICollection<T> of IntegerString) elemet is implementálja, és nem található magasabb szintű előzményfelület, a rendszer nem kezeli érvényes gyűjteményként a gyűjteményt.

  • A gyűjteménytípusokra alkalmazható az SerializableAttribute attribútum, és implementálható az ISerializable interfész. Mindkettőt figyelmen kívül hagyja a rendszer. Ha azonban a típus nem felel meg teljes mértékben a gyűjteménytípus követelményeinek (például a Add metódus hiányzik), a típus nem minősül gyűjteménytípusnak, így az SerializableAttribute attribútum és az ISerializable interfész segítségével állapítható meg, hogy a típus szerializálható-e.

  • Ha az CollectionDataContractAttribute attribútumot egy gyűjteményre alkalmazza a testreszabáshoz, az eltávolítja az SerializableAttribute előző tartalék mechanizmust. Ehelyett, ha egy testreszabott gyűjtemény nem felel meg a gyűjteménytípus követelményeinek, a rendszer kivételt InvalidDataContractException okoz. A kivételi sztring gyakran tartalmaz olyan információt, amely elmagyarázza, hogy egy adott típus miért nem tekinthető érvényes gyűjteménynek (nincs Add metódus, nincs paraméter nélküli konstruktor stb.), ezért gyakran hasznos az CollectionDataContractAttribute attribútum hibakeresési célokra történő alkalmazása.

Gyűjtemény elnevezése

Az alábbi lista a gyűjtemény elnevezési szabályainak listáját tartalmazza:

  • Az alapértelmezett névtér az összes szótárgyűjtési adatszerződéshez, valamint a primitív típusokat tartalmazó listagyűjtési adatszerződésekhez, kivéve, http://schemas.microsoft.com/2003/10/Serialization/Arrays ha felül van bírálva a névtér használatával. A beépített XSD-típusokra, valamint char, és TimespanGuid típusokra leképezett típusok erre a célra primitívnek minősülnek.

  • A nem primitív típusokat tartalmazó gyűjteménytípusok alapértelmezett névtere , kivéve, ha a névtér használatával felül van bírálva, megegyezik a gyűjteményben található típus adatszerződés-névterével.

  • A listagyűjtési adatszerződések alapértelmezett neve, kivéve, ha a névvel felül van bírálva, a "ArrayOf" sztring és a gyűjteményben található típus adatszerződésének neve. Egy általános egész számlista adatszerződésének neve például "ArrayOfint". Ne feledje, hogy az adatszerződés neve Object "anyType", ezért a nem általános listák, például ArrayList a "ArrayOfanyType" adatszerződésének neve.

A szótárgyűjtési adatszerződések alapértelmezett neve , kivéve, ha felül van bírálva Name, a "ArrayOfKeyValueOf" sztring és a kulcstípus adatszerződésének neve, majd az értéktípus adatszerződésének neve. Egy általános sztring- és egészszótár adatszerződésének neve például "ArrayOfKeyValueOfstringint". Emellett ha a kulcs vagy az értéktípusok nem primitív típusok, a rendszer hozzáfűzi a névhez a kulcs adatszerződéses névtereinek névtereit és az értéktípusokat. A névtérkivonatokról további információt az adatszerződések nevei című témakörben talál.

Minden szótárgyűjtési adatszerződéshez tartozik egy társadat-szerződés, amely egy bejegyzést jelöl a szótárban. Neve megegyezik a szótáradat-szerződés nevével, kivéve a "ArrayOf" előtagot, és a névtere megegyezik a szótáradat-szerződésével. A "ArrayOfKeyValueOfstringint" szótáradat-szerződés esetében például a "KeyValueofstringint" adatszerződés egy bejegyzést jelöl a szótárban. Ennek az adatszerződésnek a nevét testre szabhatja a ItemName tulajdonság használatával, a következő szakaszban leírtak szerint.

Az adatszerződések neveiben leírt általános típuselnevezési szabályok teljes mértékben érvényesek a gyűjteménytípusokra, azaz a Név kapcsos zárójelek használatával jelezheti az általános típusparamétereket. A zárójeleken belüli számok azonban általános paraméterekre vonatkoznak, és nem a gyűjteményben található típusokra.

Gyűjtemény testreszabása

Az attribútum alábbi alkalmazásai CollectionDataContractAttribute tiltottak, és kivételt InvalidDataContractException eredményeznek:

Polimorfizmus szabályai

Ahogy korábban említettük, a gyűjtemények attribútummal történő testreszabása megzavarhatja a CollectionDataContractAttribute gyűjtemények felcserélhetőségét. Két testre szabott gyűjteménytípus csak akkor tekinthető egyenértékűnek, ha nevük, névterük, elemnevük, valamint kulcs- és értéknevük (ha ezek szótárgyűjtemények).

A testreszabások miatt véletlenül is használhat egy gyűjtésiadat-szerződést, ahol egy másikat várnak. Ezt el kell kerülni. Tekintse meg a következő típusokat.

[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

Ebben az esetben egy példány Marks1 rendelhető hozzá testMarks. Azonban nem szabad használni, Marks2 mert az adatszerződése nem tekinthető egyenértékűnek az IList<int> adatszerződésével. Az adatszerződés neve "Marks2" és nem "ArrayOfint", az ismétlődő elem neve pedig "<mark>" és nem "<int>".

Az alábbi táblázatban szereplő szabályok a gyűjtemények polimorfikus hozzárendelésére vonatkoznak.

Deklarált típus Nem testre szabott gyűjtemény hozzárendelése Testreszabott gyűjtemény hozzárendelése
Objektum A szerződés neve szerializálva van. A szerződés neve szerializálva van.

A testreszabást használjuk.
Gyűjtési felület A szerződés neve nincs szerializálva. A szerződés neve nincs szerializálva.

A testreszabás nincs használatban.*
Nem testre szabott gyűjtemény A szerződés neve nincs szerializálva. A szerződés neve szerializálva van.

A testreszabást használjuk.**
Testreszabott gyűjtemény A szerződés neve szerializálva van. A testreszabás nincs használatban.** A szerződés neve szerializálva van.

A program a hozzárendelt típus testreszabását használja.**

*Ebben az esetben az NetDataContractSerializer osztály esetében a testreszabást kell használni. Ebben NetDataContractSerializer az esetben az osztály szerializálja a tényleges típusnevet is, így a deszerializálás a várt módon működik.

**Ezek az esetek séma érvénytelen példányokat eredményeznek, ezért el kell kerülni.

Azokban az esetekben, amikor a szerződés neve szerializálva van, a hozzárendelt gyűjteménytípusnak szerepelnie kell az ismert típusok listájában. Az ellenkezője is igaz: azokban az esetekben, amikor a név nincs szerializálva, nem szükséges hozzáadni a típust az ismert típusok listájához.

Egy származtatott típusú tömb egy alaptípusú tömbhöz rendelhető. Ebben az esetben a származtatott típus szerződésneve szerializálva lesz minden ismétlődő elemhez. Ha például egy típus Book a típusból LibraryItemszármazik, hozzárendelhet egy tömböt Book egy tömbhöz LibraryItem. Ez más gyűjteménytípusokra nem vonatkozik. Például nem rendelhet hozzá egy Generic List of BookGeneric List of LibraryItem. A példányokat tartalmazó Book példányokat azonban hozzárendelhetiGeneric List of LibraryItem. A tömb és a nem tömb esetén Book is szerepelnie kell az ismert típuslistában.

Gyűjtemények és objektumhivatkozások megőrzése

Ha egy szerializáló olyan módban működik, amelyben megőrzi az objektumhivatkozásokat, az objektumhivatkozások megőrzése a gyűjteményekre is vonatkozik. Pontosabban az objektumdentitás a gyűjteményekben található teljes gyűjtemények és egyes elemek esetében is megmarad. A szótárak esetében az objektumdentitás a kulcs/érték pár objektumai, valamint az egyes kulcs- és értékobjektumok esetében is megmarad.

Lásd még