Bekannte Typen in DatenverträgenData Contract Known Types

Die KnownTypeAttribute -Klasse ermöglicht es Ihnen, vorab die Typen anzugeben, die während der Deserialisierung in Betracht gezogen werden sollen.The KnownTypeAttribute class allows you to specify, in advance, the types that should be included for consideration during deserialization. Ein Arbeitsbeispiel finden Sie unter Known Types .For a working example, see the Known Types example.

Beim Übergeben von Parametern und Rückgabewerten zwischen einem Client und einem Dienst verwenden normalerweise beide Endpunkte sämtliche Datenverträge für die zu übertragenden Daten gemeinsam.Normally, when passing parameters and return values between a client and a service, both endpoints share all of the data contracts of the data to be transmitted. Unter den folgenden Umständen ist dies allerdings nicht der Fall:However, this is not the case in the following circumstances:

  • Der gesendete Datenvertrag wird vom erwarteten Datenvertrag abgeleitet.The sent data contract is derived from the expected data contract. Weitere Informationen finden Sie im Abschnitt zur Vererbung unter Datenvertragsäquivalenz).For more information, see the section about inheritance in Data Contract Equivalence). In diesem Fall gilt für die übertragenen Daten nicht der Datenvertrag, der vom empfangenden Endpunkt erwartet wird.In that case, the transmitted data does not have the same data contract as expected by the receiving endpoint.

  • Die zu übertragenden Informationen werden als zu einem Schnittstellentyp zugehörig deklariert, nicht als Klasse, Struktur oder Enumeration.The declared type for the information to be transmitted is an interface, as opposed to a class, structure, or enumeration. Daher kann nicht im Vorhinein bekannt sein, welcher die Schnittstelle implementierende Typ tatsächlich gesendet wird, und folglich kann der empfangende Endpunkt nicht vorab den Datenvertrag für die übermittelten Daten bestimmen.Therefore, it cannot be known in advance which type that implements the interface is actually sent and therefore, the receiving endpoint cannot determine in advance the data contract for the transmitted data.

  • Für die zu sendenden Informationen wird der Typ Objectdeklariert.The declared type for the information to be transmitted is Object. Weil jeder Typ von Objecterbt und nicht im Vorhinein bekannt sein kann, welcher die Schnittstelle implementierender Typ tatsächlich gesendet wird, und kann der empfangende Endpunkt nicht vorab den Datenvertrag für die übermittelten Daten bestimmen.Because every type inherits from Object, and it cannot be known in advance which type is actually sent, the receiving endpoint cannot determine in advance the data contract for the transmitted data. Dies ist ein Sonderfall des ersten Punkts: Jeder Datenvertrag ist vom Standardvertrag abgeleitet, d. h. einem leeren Vertrag, der für Objectgeneriert wird.This is a special case of the first item: Every data contract derives from the default, a blank data contract that is generated for Object.

  • Einige Typen, einschließlich der .NET Framework.NET Framework -Typen, verfügen über Member, die einer der drei oben genannten Kategorien angehören.Some types, which include .NET Framework.NET Framework types, have members that are in one of the preceding three categories. Zum Beispiel verwendet Hashtable den Typ Object , um die tatsächlichen Objekte in der Hashtabelle zu speichern.For example, Hashtable uses Object to store the actual objects in the hash table. Beim Serialisieren dieser Typen kann die Empfängerseite nicht im Voraus den Datenvertrag für diese Member bestimmen.When serializing these types, the receiving side cannot determine in advance the data contract for these members.

Die KnownTypeAttribute-KlasseThe KnownTypeAttribute Class

Wenn Daten beim empfangenden Endpunkt ankommen, versucht die WCF-Laufzeit ab, die Daten in eine Instanz von einem Typ der common Language Runtime (CLR) zu deserialisieren.When data arrives at a receiving endpoint, the WCF runtime attempts to deserialize the data into an instance of a common language runtime (CLR) type. Zur Auswahl des Typs, der für die Deserialisierung instanziiert wird, wird zuerst die eingehende Nachricht überprüft, um den Datenvertrag zu ermitteln, dem der Inhalt der Nachricht entspricht.The type that is instantiated for deserialization is chosen by first inspecting the incoming message to determine the data contract to which the contents of the message conform. Das Deserialisierungsmodul versucht dann, den CLR-Typ zu finden, der einen mit dem Nachrichteninhalt kompatiblen Datenvertrag implementiert.The deserialization engine then attempts to find a CLR type that implements a data contract compatible with the message contents. Die Gruppe potenzieller Typen, die das Deserialisierungsmodul während dieses Prozesses zulässt, wird als die Gruppe "bekannter Typen" des Deserialisierers bezeichnet.The set of candidate types that the deserialization engine allows for during this process is referred to as the deserializer's set of "known types."

Eine Methode, das Deserialisierungsmodul über einen Typ zu informieren, besteht im Einsatz von KnownTypeAttribute.One way to let the deserialization engine know about a type is by using the KnownTypeAttribute. Das Attribut kann nicht auf einzelne Datenmember, sondern nur auf gesamte Datenvertragstypen angewendet werden.The attribute cannot be applied to individual data members, only to whole data contract types. Das Attribut wird auf einen äußeren Typ angewendet, der eine Klasse oder eine Struktur sein kann.The attribute is applied to an outer type that can be a class or a structure. Grundsätzlich wird durch die Anwendung des Attributs ein Typ als "bekannter Typ" angegeben.In its most basic usage, applying the attribute specifies a type as a "known type." Dadurch wird der bekannte Typ Bestandteil der Gruppe bekannter Typen, wenn ein Objekt des äußeren Typs oder ein Objekt, auf das durch ein Member des äußeren Typs verwiesen wird, deserialisiert wird.This causes the known type to be a part of the set of known types whenever an object of the outer type or any object referred to through its members is being deserialized. Auf einen Typ können mehrere KnownTypeAttribute -Attribute angewendet werden.More than one KnownTypeAttribute attribute can be applied to the same type.

Bekannte Typen und PrimitiveKnown Types and Primitives

Primitive Typen sowie bestimmte Typen, die als primitiv behandelt werden (z. B. DateTime und XmlElement) sind immer "bekannt" und müssen nie mithilfe dieses Mechanismus hinzugefügt werden.Primitive types, as well as certain types treated as primitives (for example, DateTime and XmlElement) are always "known" and never have to be added through this mechanism. Arrays von primitiven Typen müssen allerdings explizit hinzugefügt werden.However, arrays of primitive types have to be added explicitly. Die meisten Auflistungen werden als äquivalent mit Arrays betrachtet.Most collections are considered equivalent to arrays. (Nicht generische Auflistungen werden als äquivalent mit Arrays von Objectbetrachtet).(Non-generic collections are considered equivalent to arrays of Object). Ein Beispiel für die Verwendung von Primitiven, primitiven Arrays und primitiven Auflistungen finden Sie in Beispiel 4.For an example of the using primitives, primitive arrays, and primitive collections, see Example 4.

Hinweis

Im Gegensatz zu anderen primitiven Typen ist die DateTimeOffset -Struktur standardmäßig kein bekannter Typ. Daher muss sie der Liste bekannter Typen manuell hinzugefügt werden.Unlike other primitive types, the DateTimeOffset structure is not a known type by default, so it must be manually added to the list of known types.

BeispieleExamples

In den folgenden Beispielen wird die Verwendung der KnownTypeAttribute -Klasse veranschaulicht.The following examples show the KnownTypeAttribute class in use.

Beispiel 1Example 1

Es sind drei Klassen mit einer Vererbungsbeziehung gegeben.There are three classes with an inheritance relationship.

[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

Die folgende CompanyLogo -Klasse kann serialisiert werden. Sie kann jedoch nicht deserialisiert werden, wenn der ShapeOfLogo -Member auf ein CircleType -Objekt oder ein TriangleType -Objekt festgelegt wird, weil das Deserialisierungsmodul keine Typen mit Datenverträgen namens "Circle" oder "Triangle" erkennt.The following CompanyLogo class can be serialized, but cannot be deserialized if the ShapeOfLogo member is set to either a CircleType or a TriangleType object, because the deserialization engine does not recognize any types with data contract names "Circle" or "Triangle."

[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

Im folgenden Code wird gezeigt, wie der CompanyLogo -Typ richtig geschrieben wird.The correct way to write the CompanyLogo type is shown in the following code.

[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

Jedes Mal, wenn der äußere Typ CompanyLogo2 deserialisiert wird, wird das Deserialisierungsmodul über CircleType und TriangleType informiert und kann daher die passenden Typen für die Datenverträge namens "Circle" und "Triangle" finden.Whenever the outer type CompanyLogo2 is being deserialized, the deserialization engine knows about CircleType and TriangleType and, therefore, is able to find matching types for the "Circle" and "Triangle" data contracts.

Beispiel 2Example 2

Im folgenden Beispiel ist sowohl CustomerTypeA als auch CustomerTypeB der Datenvertrag Customer zugeordnet. Trotz dieser Tatsache wird jedes Mal eine Instanz von CustomerTypeB erstellt, wenn ein PurchaseOrder -Objekt deserialisiert wird, weil das Deserialisierungsmodul nur CustomerTypeB kennt.In the following example, even though both CustomerTypeA and CustomerTypeB have the Customer data contract, an instance of CustomerTypeB is created whenever a PurchaseOrder is deserialized, because only CustomerTypeB is known to the deserialization engine.

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

Beispiel 3Example 3

Im folgenden Beispiel speichert ein Hashtable seinen Inhalt intern als Object.In the following example, a Hashtable stores its contents internally as Object. Um eine Hashtabelle erfolgreich deserialisieren zu können, muss das Deserialisierungsmodul die Gruppe möglicher Typen kennen, die hier vorkommen können.To successfully deserialize a hash table, the deserialization engine must know the set of possible types that can occur there. In diesem Fall wissen wir im Vorhinein, dass nur Book -Objekte und Magazine -Objekte im Cataloggespeichert werden. Daher werden sie mithilfe des KnownTypeAttribute -Attributs hinzugefügt.In this case, we know in advance that only Book and Magazine objects are stored in the Catalog, so those are added using the KnownTypeAttribute attribute.

[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

Beispiel 4Example 4

Im folgenden Beispiel wird eine Zahl und ein Vorgang, der mit der Zahl ausgeführt werden soll, in einem Datenvertrag gespeichert.In the following example, a data contract stores a number and an operation to perform on the number. Der Numbers -Datenmember kann eine ganze Zahl, ein Array von ganzen Zahlen oder ein Objekt des Typs List<T> sein, das ganze Zahlen enthält.The Numbers data member can be an integer, an array of integers, or a List<T> that contains integers.

Achtung

Dies funktioniert nur auf Clientseite, wenn zum Generieren eines WCF-Proxys SVCUTIL.EXE verwendet wird.This will only work on the client side if SVCUTIL.EXE is used to generate a WCF proxy. SVCUTIL.EXE ruft Metadaten vom Dienst ab, einschließlich aller bekannter Typen.SVCUTIL.EXE retrieves metadata from the service including any known types. Ohne diese Informationen kann ein Client die Typen nicht deserialisieren.Without this information a client will not be able to deserialize the types.

[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

Dies ist der Anwendungscode.This is the application code.

// 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

Bekannte Typen, Vererbung und SchnittstellenKnown Types, Inheritance, and Interfaces

Wenn ein bekannter Typ mithilfe des KnownTypeAttribute -Attributs mit einem bestimmten Typ verknüpft wird, wird der bekannte Typ auch mit allen von diesem Typ abgeleiteten Typen verknüpft.When a known type is associated with a particular type using the KnownTypeAttribute attribute, the known type is also associated with all of the derived types of that type. Beachten Sie beispielsweise folgenden Code.For example, see the following code.

[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

Die DoubleDrawing -Klasse erfordert nicht, dass das KnownTypeAttribute -Attribut mit Square und Circle im AdditionalShape -Feld verwendet wird, weil diese Attribute bereits auf die Basisklasse (Drawing) angewendet wurden.The DoubleDrawing class does not require the KnownTypeAttribute attribute to use Square and Circle in the AdditionalShape field, because the base class (Drawing) already has these attributes applied.

Bekannte Typen können nur Klassen und Strukturen, nicht jedoch Schnittstellen, zugeordnet werden.Known types can be associated only with classes and structures, not interfaces.

Bekannte Typen, die offene generische Methoden verwendenKnown Types Using Open Generic Methods

Es ist möglicherweise notwendig, einen generischen Typ als bekannten Typ hinzuzufügen.It may be necessary to add a generic type as a known type. Ein offener generischer Typ kann dem KnownTypeAttribute -Attribut nicht als Parameter übergeben werden.However, an open generic type cannot be passed as a parameter to the KnownTypeAttribute attribute.

Dieses Problem lässt sich mithilfe eines alternativen Mechanismus lösen: Schreiben Sie eine Methode, die eine Liste derjenigen Typen zurückgibt, welche der Auflistung bekannter Typen hinzugefügt werden können.This problem can be solved by using an alternative mechanism: Write a method that returns a list of types to add to the known types collection. Wegen einigen Beschränkungen wird der Name der Methode dann als Zeichenfolgenargument für das KnownTypeAttribute -Attribut angegeben.The name of the method is then specified as a string argument to the KnownTypeAttribute attribute due to some restrictions.

Diese Methode muss für den Typ vorhanden sein, auf den das KnownTypeAttribute -Attribut angewendet wird. Sie muss statisch sein, darf keine Parameter annehmen und muss ein Objekt zurückgeben, das der IEnumerable -Schnittstelle von Typezugewiesen werden kann.The method must exist on the type to which the KnownTypeAttribute attribute is applied, must be static, must accept no parameters, and must return an object that can be assigned to IEnumerable of Type.

Es ist nicht möglich, das KnownTypeAttribute -Attribut mit einem Methodennamen und KnownTypeAttribute -Attribute mit tatsächlichen Typen für den gleichen Typ zu kombinieren.You cannot combine the KnownTypeAttribute attribute with a method name and KnownTypeAttribute attributes with actual types on the same type. Weiterhin ist es nicht möglich, mehr als ein KnownTypeAttribute -Attribut mit einem Methodennamen auf den gleichen Typ anzuwenden.Furthermore, you cannot apply more than one KnownTypeAttribute with a method name to the same type.

Siehe folgende Klasse.See the following class.

[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

Das theDrawing -Feld enthält Instanzen der generischen Klasse ColorDrawing und der generischen Klasse BlackAndWhiteDrawing, die beide von der generischen Klasse Drawingabgeleitet sind.The theDrawing field contains instances of a generic class ColorDrawing and a generic class BlackAndWhiteDrawing, both of which inherit from a generic class Drawing. Normalerweise müssen beide Klassen den bekannten Typen hinzugefügt werden, aber der folgende Code stellt keine für Attribute gültige Syntax dar.Normally, both must be added to known types, but the following is not valid syntax for attributes.

// 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)))>  

Daher muss eine Methode erstellt werden, die diese Typen zurückgibt.Thus, a method must be created to return these types. Im folgenden Code wird gezeigt, wie dieser Typ richtig geschrieben wird.The correct way to write this type, then, is shown in the following code.

[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

Weitere Verfahren zum Hinzufügen bekannter TypenAdditional Ways to Add Known Types

Darüber hinaus können bekannte Typen durch eine Konfigurationsdatei hinzugefügt werden.Additionally, known types can be added through a configuration file. Dies ist hilfreich, wenn Sie nicht den Typ steuern, der, wie z. B. bei Verwendung von Drittanbieter-Typbibliotheken mit Windows Communication Foundation (WCF), dessen Deserialisierung bekannte Typen erfordert.This is useful when you do not control the type that requires known types for proper deserialization, such as when using third-party type libraries with Windows Communication Foundation (WCF).

Die folgende Konfigurationsdatei zeigt, wie in einer Konfigurationsdatei ein bekannter Typ angegeben wird.The following configuration file shows how to specify a known type in a configuration file.

<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>

In der vorangegangenen Konfigurationsdatei wird ein Datenvertragstyp mit der Bezeichnung MyCompany.Library.Shape deklariert, um MyCompany.Library.Circle als bekannten Typ zu erhalten.In the preceding configuration file a data contract type called MyCompany.Library.Shape is declared to have MyCompany.Library.Circle as a known type.

Siehe auchSee Also

KnownTypeAttribute
Hashtable
Object
DataContractSerializer
KnownTypes
Bekannte TypenKnown Types
DatenvertragsäquivalenzData Contract Equivalence
Entwerfen von DienstverträgenDesigning Service Contracts