Types connus de contrats de donnéesData Contract Known Types

La classe KnownTypeAttribute vous permet de spécifier, en avance, les types qui doivent être inclus pour être pris en compte pendant la désérialisation.The KnownTypeAttribute class allows you to specify, in advance, the types that should be included for consideration during deserialization. Pour obtenir un exemple fonctionnel, consultez l’exemple Known Types .For a working example, see the Known Types example.

Normalement, lors du passage des paramètres et des valeurs de retour entre un client et un service, les deux points de terminaison partagent tous les contrats de données des données à transmettre.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. Toutefois, ce n'est pas le cas dans les circonstances suivantes :However, this is not the case in the following circumstances:

  • Le contrat de données envoyé est dérivé du contrat de données attendu.The sent data contract is derived from the expected data contract. Pour plus d’informations, consultez la section relative à l’héritage dans équivalence des contrats de données.For more information, see the section about inheritance in Data Contract Equivalence). Dans ce cas, les données transmises n'ont pas le même contrat de données que celui attendu par le point de terminaison de réception.In that case, the transmitted data does not have the same data contract as expected by the receiving endpoint.

  • Le type déclaré pour les informations à transmettre est une interface, par opposition à une classe, une structure ou une énumération.The declared type for the information to be transmitted is an interface, as opposed to a class, structure, or enumeration. Par conséquent, il n'est pas possible de connaître à l'avance quel type implémentant l'interface est envoyé réellement et, par conséquent, le point de terminaison de réception ne peut pas déterminer, à l'avance, le contrat de données pour les données transmises.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.

  • Le type déclaré pour les informations à transmettre est Object.The declared type for the information to be transmitted is Object. Comme chaque type hérite de Object, et il n'est pas possible de connaître à l'avance quel type est envoyé réellement, le point de terminaison de réception ne peut pas déterminer à l'avance le contrat de données pour les données transmises.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. Il s’agit d’un cas spécial du premier élément: Chaque contrat de données dérive de la valeur par défaut, un contrat de données vide Objectgénéré pour.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.

  • Certains types, y compris les types de .NET Framework, ont des membres qui se trouvent dans l’une des trois catégories précédentes.Some types, which include .NET Framework types, have members that are in one of the preceding three categories. Par exemple, Hashtable utilise Object pour stocker les objets réels dans la table de hachage.For example, Hashtable uses Object to store the actual objects in the hash table. Lors de la sérialisation de ces types, le côté réception ne peut pas déterminer à l'avance le contrat de données pour ces membres.When serializing these types, the receiving side cannot determine in advance the data contract for these members.

Classe KnownTypeAttributeThe KnownTypeAttribute Class

Lorsque les données arrivent à un point de terminaison de réception, le runtime WCF tente de désérialiser les données dans une instance d’un type de common language runtime (CLR).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. Le type instancié pour la désérialisation est choisi en inspectant d'abord le message entrant pour déterminer le contrat de données auquel le contenu du message se conforme.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. Le moteur de désérialisation essaie ensuite de rechercher un type CLR qui implémente un contrat de données compatible avec le contenu de message.The deserialization engine then attempts to find a CLR type that implements a data contract compatible with the message contents. Le jeu des types de candidat que le moteur de désérialisation autorise pendant ce processus porte le nom du jeu du désérialiseur des « types connus ».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."

Une façon d'informer le moteur de désérialisation d'un type est d'utiliser KnownTypeAttribute.One way to let the deserialization engine know about a type is by using the KnownTypeAttribute. L'attribut ne peut pas être appliqué aux membres de données individuels, uniquement aux types de contrat de données entiers.The attribute cannot be applied to individual data members, only to whole data contract types. L'attribut est appliqué à un type externe qui peut être une classe ou une structure.The attribute is applied to an outer type that can be a class or a structure. Dans son utilisation la plus simple, l'application de l'attribut spécifie un type en tant que « type connu ».In its most basic usage, applying the attribute specifies a type as a "known type." Cela entraîne l'intégration du type connu dans un jeu de types connus à chaque fois qu'un objet du type externe ou tout objet référencé via ses membres est désérialisé.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. Plusieurs attributs KnownTypeAttribute peuvent être appliqués au même type.More than one KnownTypeAttribute attribute can be applied to the same type.

Types et primitives connusKnown Types and Primitives

Les types primitifs, ainsi que certains types traités comme des primitives (par exemple, DateTime et XmlElement) sont toujours « connus » et il n'est jamais nécessaire de les ajouter par le biais de ce mécanisme.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. Cependant, les tableaux de types primitifs doivent être ajouté explicitement.However, arrays of primitive types have to be added explicitly. La plupart des collections sont considérées comme équivalentes aux tableaux.Most collections are considered equivalent to arrays. (Les collections non génériques sont considérées comme équivalentes aux tableaux de Object).(Non-generic collections are considered equivalent to arrays of Object). Pour un exemple de l'utilisation des primitives, des tableaux de primitives et des collections de primitives, consultez l'exemple 4.For an example of the using primitives, primitive arrays, and primitive collections, see Example 4.

Notes

Contrairement à d'autres types de primitive, la structure DateTimeOffset n'est pas un type connu par défaut, donc elle doit être ajoutée manuellement à la liste de types connus.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.

ExemplesExamples

Voici quelques exemples de la classe KnownTypeAttribute employée.The following examples show the KnownTypeAttribute class in use.

Exemple 1Example 1

Il existe trois classes avec une relation d'héritage.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

La classe CompanyLogo suivante peut être sérialisée, mais ne peut pas être désérialisée si le membre ShapeOfLogo a pour valeur un CircleType ou un objet TriangleType , étant donné que le moteur de désérialisation ne reconnaît pas de types avec les noms de contrat de données « Cercle » ou « Triangle ».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

La méthode correcte pour écrire le type CompanyLogo est indiquée dans le code suivant.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

Toutes les fois que le type CompanyLogo2 externe est désérialisé, le moteur de désérialisation connaît CircleType et TriangleType et, par conséquent, est en mesure de rechercher des types correspondants pour les contrats de données « Cercle » ou « Triangle ».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.

Exemple 2Example 2

Dans l'exemple suivant, même si CustomerTypeA et CustomerTypeB ont le contrat de données Customer , une instance de CustomerTypeB est créée à chaque fois qu'un PurchaseOrder est désérialisé, car seul CustomerTypeB est connu du moteur de désérialisation.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

Exemple 3Example 3

Dans l'exemple suivant, un Hashtable stocke en interne son contenu sous la forme d'un Object.In the following example, a Hashtable stores its contents internally as Object. Pour désérialiser une table de hachage correctement, le moteur de désérialisation doit connaître le jeu de types possibles qui peuvent se produire à cet endroit.To successfully deserialize a hash table, the deserialization engine must know the set of possible types that can occur there. Dans ce cas, nous savons à l'avance que seuls les objets Book et Magazine sont stockés dans le Catalog, par conséquent ils sont ajoutés à l'aide de l'attribut KnownTypeAttribute .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

Exemple 4Example 4

Dans l'exemple suivant, un contrat de données stocke un nombre et une opération à effectuer sur le nombre.In the following example, a data contract stores a number and an operation to perform on the number. Le membre de données Numbers peut être un entier, un tableau d'entiers ou un objet List<T> qui contient des entiers.The Numbers data member can be an integer, an array of integers, or a List<T> that contains integers.

Attention

Cela ne fonctionnera que du côté client si SVCUTIL.EXE est utilisé pour générer un proxy WCF.This will only work on the client side if SVCUTIL.EXE is used to generate a WCF proxy. SVCUTIL.EXE récupère des métadonnées du service, notamment tous les types connus.SVCUTIL.EXE retrieves metadata from the service including any known types. Sans ces informations, un client ne sera pas en mesure de désérialiser les types.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

Voici le code d'application.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

Types, héritage et interfaces connusKnown Types, Inheritance, and Interfaces

Lorsqu'un type connu est associé à un type particulier à l'aide de l'attribut KnownTypeAttribute , le type connu est également associé à tous les types dérivés de ce type.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. Par exemple, consultez le code suivant.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

La classe DoubleDrawing ne requiert pas que l'attribut KnownTypeAttribute utilise Square et Circle dans le champ AdditionalShape , parce que la classe de base (Drawing) a déjà ces attributs appliqués.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.

Les types connus peuvent être associés uniquement à des classes et des structures, pas des interfaces.Known types can be associated only with classes and structures, not interfaces.

Types connus qui utilisent des méthodes génériques ouvertesKnown Types Using Open Generic Methods

Il peut être nécessaire d'ajouter un type générique en tant que type connu.It may be necessary to add a generic type as a known type. Toutefois, un type générique ouvert ne peut pas être passé en tant que paramètre à l'attribut KnownTypeAttribute .However, an open generic type cannot be passed as a parameter to the KnownTypeAttribute attribute.

Ce problème peut être résolu à l’aide d’un autre mécanisme: Écrivez une méthode qui retourne une liste de types à ajouter à la collection de types connus.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. Le nom de la méthode est spécifié comme un argument de chaîne à l'attribut KnownTypeAttribute en raison de certaines restrictions.The name of the method is then specified as a string argument to the KnownTypeAttribute attribute due to some restrictions.

La méthode doit exister sur le type auquel l'attribut KnownTypeAttribute est appliqué, il doit être statique, il ne doit pas accepter de paramètres et doit retourner un objet qui peut être assigné à IEnumerable de Type.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.

Vous ne pouvez pas associer l'attribut KnownTypeAttribute avec un nom de méthode et des attributs KnownTypeAttribute avec des types réels sur le même type.You cannot combine the KnownTypeAttribute attribute with a method name and KnownTypeAttribute attributes with actual types on the same type. En outre, vous ne pouvez pas appliquer plusieurs KnownTypeAttribute avec un nom de méthode au même type.Furthermore, you cannot apply more than one KnownTypeAttribute with a method name to the same type.

Consultez la classe suivante.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

Le champ theDrawing contient des instances d'une classe générique ColorDrawing et d'une classe générique BlackAndWhiteDrawingqui héritent toutes les deux d'une classe générique Drawing.The theDrawing field contains instances of a generic class ColorDrawing and a generic class BlackAndWhiteDrawing, both of which inherit from a generic class Drawing. Normalement, les deux doivent être ajoutées aux types connus, mais les éléments suivants ne sont pas une syntaxe valide pour des attributs.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)))>  

Donc, une méthode doit être créée pour retourner ces types.Thus, a method must be created to return these types. La méthode correcte pour écrire ce type est indiquée dans le code suivant.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

Méthodes supplémentaires pour ajouter des types connusAdditional Ways to Add Known Types

En outre, les types connus peuvent être ajoutés par le biais d'un fichier de configuration.Additionally, known types can be added through a configuration file. Cela est utile lorsque vous ne contrôlez pas le type qui requiert des types connus pour une désérialisation appropriée, par exemple lors de l’utilisation de bibliothèques de types tiers avec Windows Communication Foundation (WCF).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).

Le fichier de configuration suivant indique comment spécifier un type connu dans un fichier de configuration.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>

Un type de contrat de données dans le fichier de configuration précédent appelé MyCompany.Library.Shape est déclaré comme ayant MyCompany.Library.Circle comme type connu.In the preceding configuration file a data contract type called MyCompany.Library.Shape is declared to have MyCompany.Library.Circle as a known type.

Voir aussiSee also