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


Adatszerződés ismert típusai

Az KnownTypeAttribute osztály segítségével előre megadhatja azokat a típusokat, amelyeket figyelembe kell venni a deszerializálás során. Egy működő példáért tekintse meg az Ismert típusok példát.

Általában, amikor paramétereket ad át, és értékeket ad vissza egy ügyfél és egy szolgáltatás között, mindkét végpont megosztja a továbbítandó adatok összes adatszerződését. A következő körülmények között azonban nem ez a helyzet:

  • Az elküldött adatszerződés a várt adatszerződésből származik. További információkért tekintse meg az adatszerződések egyenértékűségének örökléséről szóló szakaszt. Ebben az esetben a továbbított adatok nem rendelkeznek a fogadó végpont által elvárt adatszerződéssel.

  • Az továbbítandó információk deklarált típusa egy interfész, szemben az osztályokkal, szerkezetekkel vagy enumerálással. Ezért nem lehet előre tudni, hogy melyik típus implementálja az interfészt, ezért a fogadó végpont nem tudja előre meghatározni a továbbított adatokra vonatkozó adatszerződést.

  • A továbbítandó információk deklarált típusa a Objectkövetkező. Mivel minden típus öröklődik, Objectés nem lehet előre tudni, hogy melyik típust küldi el a rendszer, a fogadó végpont nem tudja előre meghatározni a továbbított adatokra vonatkozó adatszerződést. Ez az első elem különleges esete: Minden adatszerződés az alapértelmezett, egy üres adatszerződésből származik, amely a következőhöz Objectjön létre: .

  • Egyes típusok, amelyek .NET-keretrendszer típusokat is tartalmaznak, az előző három kategóriában szereplő tagokkal rendelkeznek. Például Hashtable a tényleges objektumok tárolására használható Object a kivonattáblában. Az ilyen típusok szerializálásakor a fogadó fél nem tudja előre meghatározni a tagokra vonatkozó adatszerződést.

A KnownTypeAttribute osztály

Amikor az adatok fogadó végpontra érkeznek, a WCF-futtatókörnyezet megpróbálja deszerializálni az adatokat egy általános nyelvi futtatókörnyezet (CLR) típusú példányba. A deszerializáláshoz példányosított típust úgy választja ki, hogy először megvizsgálja a bejövő üzenetet annak az adatszerződésnek a meghatározásához, amelynek az üzenet tartalma megfelel. A deszerializálási motor ezután megpróbál megkeresni egy OLYAN CLR-típust, amely az üzenet tartalmával kompatibilis adatszerződést valósít meg. A deszerializálási motor által a folyamat során lehetővé tetsző típusokat a deszerializáló "ismert típusok" készletének nevezzük.

Az egyik módja annak, hogy a deszerializálási motor tudassa egy típussal a KnownTypeAttribute. Az attribútum nem alkalmazható az egyes adattagokra, csak teljes adatszerződés-típusokra. Az attribútum egy külső típusra lesz alkalmazva, amely lehet osztály vagy struktúra. A legalapvetőbb használatban az attribútum alkalmazása egy típust "ismert típusként" határoz meg. Ez azt eredményezi, hogy az ismert típus az ismert típusok csoportjának része lesz, amikor a külső típusú objektumot vagy a tagjain keresztül hivatkozott objektumot deszerializálják. KnownTypeAttribute Több attribútum is alkalmazható ugyanahhoz a típushoz.

Ismert típusok és primitívek

A primitív típusok, valamint a primitívként kezelt egyes típusok (például és XmlElement) mindig "ismertek", DateTime és soha nem kell ezen a mechanizmuson keresztül hozzáadni. A primitív típusú tömböket azonban explicit módon kell hozzáadni. A gyűjtemények többsége tömböknek felel meg. (A nem általános gyűjtemények egyenértékűek a tömbökével Object. Példa a primitívek, primitív tömbök és primitív gyűjtemények használatára: 4. példa.

Feljegyzés

A többi primitív típustól eltérően a DateTimeOffset struktúra alapértelmezés szerint nem ismert típus, ezért manuálisan kell hozzáadni az ismert típusok listájához.

Példák

Az alábbi példák a használatban lévő osztályt KnownTypeAttribute mutatják be.

1. példa

Három osztály van öröklési kapcsolatban.

[DataContract]
public class Shape { }

[DataContract(Name = "Circle")]
public class CircleType : Shape { }

[DataContract(Name = "Triangle")]
public class TriangleType : Shape { }
<DataContract()> _
Public Class Shape
End Class

<DataContract(Name:="Circle")> _
Public Class CircleType
    Inherits Shape
End Class
<DataContract(Name:="Triangle")> _
Public Class TriangleType
    Inherits Shape
End Class

A következő CompanyLogo osztály szerializálható, de nem deszerializálható, ha a ShapeOfLogo tag egy vagy egy TriangleType objektumra CircleType van állítva, mert a deszerializálási motor nem ismer fel olyan típusokat, amelyek "Circle" vagy "Triangle" nevű adatszerződéssel rendelkeznek.

[DataContract]
public class CompanyLogo
{
    [DataMember]
    private Shape ShapeOfLogo;
    [DataMember]
    private int ColorOfLogo;
}
<DataContract()> _
Public Class CompanyLogo
    <DataMember()> _
    Private ShapeOfLogo As Shape
    <DataMember()> _
    Private ColorOfLogo As Integer
End Class

A típus megírásának CompanyLogo helyes módja az alábbi kódban látható.

[DataContract]
[KnownType(typeof(CircleType))]
[KnownType(typeof(TriangleType))]
public class CompanyLogo2
{
    [DataMember]
    private Shape ShapeOfLogo;
    [DataMember]
    private int ColorOfLogo;
}
<DataContract(), KnownType(GetType(CircleType)), KnownType(GetType(TriangleType))> _
Public Class CompanyLogo2
    <DataMember()> _
    Private ShapeOfLogo As Shape
    <DataMember()> _
    Private ColorOfLogo As Integer
End Class

Amikor a külső típust CompanyLogo2 deszerializálják, a deszerializálási motor tud róla CircleType , és TriangleType ezért képes megtalálni a "Circle" és a "Triangle" adatszerződések megfelelő típusait.

2. példa

A következő példában annak ellenére, hogy mind a kettő CustomerTypeACustomerTypeB , mind az Customer adatszerződéssel rendelkezik, a rendszer akkor hoz létre példányt CustomerTypeBPurchaseOrder , amikor deszerializál egy példányt, mert csak CustomerTypeB a deszerializálási motor ismeri.

public interface ICustomerInfo
{
    string ReturnCustomerName();
}

[DataContract(Name = "Customer")]
public class CustomerTypeA : ICustomerInfo
{
    public string ReturnCustomerName()
    {
        return "no name";
    }
}

[DataContract(Name = "Customer")]
public class CustomerTypeB : ICustomerInfo
{
    public string ReturnCustomerName()
    {
        return "no name";
    }
}

[DataContract]
[KnownType(typeof(CustomerTypeB))]
public class PurchaseOrder
{
    [DataMember]
    ICustomerInfo buyer;

    [DataMember]
    int amount;
}
Public Interface ICustomerInfo
    Function ReturnCustomerName() As String
End Interface

<DataContract(Name:="Customer")> _
Public Class CustomerTypeA
    Implements ICustomerInfo
    Public Function ReturnCustomerName() _
    As String Implements ICustomerInfo.ReturnCustomerName
        Return "no name"
    End Function
End Class

<DataContract(Name:="Customer")> _
Public Class CustomerTypeB
    Implements ICustomerInfo
    Public Function ReturnCustomerName() _
    As String Implements ICustomerInfo.ReturnCustomerName
        Return "no name"
    End Function
End Class

<DataContract(), KnownType(GetType(CustomerTypeB))> _
Public Class PurchaseOrder
    <DataMember()> _
    Private buyer As ICustomerInfo

    <DataMember()> _
    Private amount As Integer
End Class

3. példa

A következő példában a Hashtable tartalom belsőleg a következőképpen van tárolva Object: . A kivonattáblák sikeres deszerializálásához a deszerializálási motornak ismernie kell az ott előforduló lehetséges típusokat. Ebben az esetben előre tudjuk, hogy csak Book és Magazine az objektumok vannak tárolva a Catalog, így azokat az KnownTypeAttribute attribútum használatával adjuk hozzá.

[DataContract]
public class Book { }

[DataContract]
public class Magazine { }

[DataContract]
[KnownType(typeof(Book))]
[KnownType(typeof(Magazine))]
public class LibraryCatalog
{
    [DataMember]
    System.Collections.Hashtable theCatalog;
}
<DataContract()> _
Public Class Book
End Class

<DataContract()> _
Public Class Magazine
End Class

<DataContract(), KnownType(GetType(Book)), KnownType(GetType(Magazine))> _
Public Class LibraryCatalog
    <DataMember()> _
    Private theCatalog As System.Collections.Hashtable
End Class

4. példa

Az alábbi példában egy adatszerződés egy számot és egy műveletet tárol a számon. Az Numbers adattag lehet egész szám, egész számok tömbje vagy List<T> egész számokat tartalmazó tömb.

Figyelemfelhívás

Ez csak akkor működik az ügyféloldalon, ha SVCUTIL.EXE használ egy WCF-proxy létrehozásához. SVCUTIL.EXE lekéri a metaadatokat a szolgáltatásból, beleértve az ismert típusokat is. Ezen információk nélkül az ügyfél nem tudja deszerializálni a típusokat.

[DataContract]
[KnownType(typeof(int[]))]
public class MathOperationData
{
    private object numberValue;
    [DataMember]
    public object Numbers
    {
        get { return numberValue; }
        set { numberValue = value; }
    }
    //[DataMember]
    //public Operation Operation;
}
<DataContract(), KnownType(GetType(Integer()))> _
Public Class MathOperationData
    Private numberValue As Object

    <DataMember()> _
    Public Property Numbers() As Object
        Get
            Return numberValue
        End Get
        Set(ByVal value As Object)
            numberValue = value
        End Set
    End Property
End Class

Ez az alkalmazás kódja.

// This is in the service application code:
static void Run()
{

    MathOperationData md = new MathOperationData();

    // This will serialize and deserialize successfully because primitive
    // types like int are always known.
    int a = 100;
    md.Numbers = a;

    // This will serialize and deserialize successfully because the array of
    // integers was added to known types.
    int[] b = new int[100];
    md.Numbers = b;

    // This will serialize and deserialize successfully because the generic
    // List<int> is equivalent to int[], which was added to known types.
    List<int> c = new List<int>();
    md.Numbers = c;
    // This will serialize but will not deserialize successfully because
    // ArrayList is a non-generic collection, which is equivalent to
    // an array of type object. To make it succeed, object[]
    // must be added to the known types.
    ArrayList d = new ArrayList();
    md.Numbers = d;
}
' This is in the service application code:
Shared Sub Run()
    Dim md As New MathOperationData()
    ' This will serialize and deserialize successfully because primitive 
    ' types like int are always known.
    Dim a As Integer = 100
    md.Numbers = a

    ' This will serialize and deserialize successfully because the array of 
    ' integers was added to known types.
    Dim b(99) As Integer
    md.Numbers = b

    ' This will serialize and deserialize successfully because the generic 
    ' List(Of Integer) is equivalent to Integer(), which was added to known types.
    Dim c As List(Of Integer) = New List(Of Integer)()
    md.Numbers = c
    ' This will serialize but will not deserialize successfully because 
    ' ArrayList is a non-generic collection, which is equivalent to 
    ' an array of type object. To make it succeed, object[]
    ' must be added to the known types.
    Dim d As New ArrayList()
    md.Numbers = d

End Sub

Ismert típusok, öröklés és interfészek

Ha egy ismert típus egy adott típushoz van társítva az KnownTypeAttribute attribútum használatával, az ismert típus az adott típus összes származtatott típusához is társítva lesz. Lásd például a következő kódot.

[DataContract]
[KnownType(typeof(Square))]
[KnownType(typeof(Circle))]
public class MyDrawing
{
    [DataMember]
    private object Shape;
    [DataMember]
    private int Color;
}

[DataContract]
public class DoubleDrawing : MyDrawing
{
    [DataMember]
    private object additionalShape;
}
<DataContract(), KnownType(GetType(Square)), KnownType(GetType(Circle))> _
Public Class MyDrawing
    <DataMember()> _
    Private Shape As Object
    <DataMember()> _
    Private Color As Integer
End Class

<DataContract()> _
Public Class DoubleDrawing
    Inherits MyDrawing
    <DataMember()> _
    Private additionalShape As Object
End Class

Az DoubleDrawing osztálynak nincs szüksége az KnownTypeAttribute attribútum használatára és Circle a AdditionalShape mezőben való használatáraSquare, mert az alaposztály (Drawing) már alkalmazza ezeket az attribútumokat.

Az ismert típusok csak osztályokhoz és struktúrákhoz társíthatók, interfészekhez nem.

Ismert típusok open generic metódusokkal

Előfordulhat, hogy általános típust kell hozzáadni ismert típusként. Nyitott általános típus azonban nem adható át paraméterként az KnownTypeAttribute attribútumnak.

Ez a probléma egy alternatív mechanizmussal oldható meg: Írjon egy metódust, amely visszaadja az ismert típusok gyűjteményéhez hozzáadni kívánt típusok listáját. A metódus neve ezután bizonyos korlátozások miatt sztringargumentumként lesz megadva az KnownTypeAttribute attribútumhoz.

A metódusnak azon a típuson kell léteznie, amelyre az KnownTypeAttribute attribútumot alkalmazza, statikusnak kell lennie, nem szabad paramétereket elfogadnia, és egy olyan objektumot kell visszaadnia IEnumerableType, amelyhez hozzárendelhető.

Az attribútum nem kombinálható KnownTypeAttribute metódusnévvel és KnownTypeAttribute attribútumokkal az azonos típusú tényleges típusokkal. Emellett nem alkalmazhat egynél KnownTypeAttribute több metódusnevet ugyanarra a típusra.

Lásd az alábbi osztályt.

[DataContract]
public class DrawingRecord<T>
{
    [DataMember]
    private T theData;
    [DataMember]
    private GenericDrawing<T> theDrawing;
}
<DataContract()> _
Public Class DrawingRecord(Of T)
    <DataMember()> _
    Private theData As T
    <DataMember()> _
    Private theDrawing As GenericDrawing(Of T)
End Class

A theDrawing mező egy általános osztály és egy általános osztály ColorDrawingBlackAndWhiteDrawingpéldányait tartalmazza, amelyek mindegyike egy általános osztálytól Drawingöröklődik. Általában mindkettőt hozzá kell adni az ismert típusokhoz, de az alábbiak nem érvényesek az attribútumok szintaxisára.

// Invalid syntax for attributes:  
// [KnownType(typeof(ColorDrawing<T>))]  
// [KnownType(typeof(BlackAndWhiteDrawing<T>))]  
' Invalid syntax for attributes:  
' <KnownType(GetType(ColorDrawing(Of T))), _  
' KnownType(GetType(BlackAndWhiteDrawing(Of T)))>  

Ezért létre kell hozni egy metódust, amely visszaadja ezeket a típusokat. A típus megírásának helyes módja az alábbi kódban jelenik meg.

[DataContract]
[KnownType("GetKnownType")]
public class DrawingRecord2<T>
{
    [DataMember]
    private T TheData;
    [DataMember]
    private GenericDrawing<T> TheDrawing;

    private static Type[] GetKnownType()
    {
        Type[] t = new Type[2];
        t[0] = typeof(ColorDrawing<T>);
        t[1] = typeof(BlackAndWhiteDrawing<T>);
        return t;
    }
}
<DataContract(), KnownType("GetKnownType")> _
Public Class DrawingRecord2(Of T)
    Private TheData As T
    Private TheDrawing As GenericDrawing(Of T)

    Private Shared Function GetKnownType() As Type()
        Dim t(1) As Type
        t(0) = GetType(ColorDrawing(Of T))
        t(1) = GetType(BlackAndWhiteDrawing(Of T))
        Return t
    End Function
End Class

Ismert típusok hozzáadásának további módjai

Emellett az ismert típusok egy konfigurációs fájlon keresztül is hozzáadhatók. Ez akkor hasznos, ha nem szabályozza azt a típust, amely a megfelelő deszerializáláshoz ismert típusokat igényel, például ha külső típuskódtárakat használ a Windows Communication Foundation (WCF) használatával.

Az alábbi konfigurációs fájl bemutatja, hogyan adhat meg egy ismert típust egy konfigurációs fájlban.

<configuration>

<system.runtime.serialization>

<dataContractSerializer>

<declaredTypes>

<add type="MyCompany.Library.Shape,

MyAssembly, Version=2.0.0.0, Culture=neutral,

PublicKeyToken=XXXXXX, processorArchitecture=MSIL">

<knownType type="MyCompany.Library.Circle,

MyAssembly, Version=2.0.0.0, Culture=neutral,

PublicKeyToken=XXXXXX, processorArchitecture=MSIL"/>

</add>

</declaredTypes>

</dataContractSerializer>

</system.runtime.serialization>

</configuration>

Az előző konfigurációs fájlban a hívott MyCompany.Library.Shape adatszerződés típusa ismert típusként van deklarálva MyCompany.Library.Circle .

Lásd még