Equivalencia del contrato de datos

Para que un cliente envíe correctamente datos de un cierto tipo a un servicio, o para que un servicio envíe correctamente datos a un cliente, el tipo enviado no tiene que existir necesariamente en el extremo receptor. El único requisito es que los contratos de datos de ambos tipos sean equivalentes. (En ocasiones, no se requiere una equivalencia estricta, como se explica en Control de versiones de contratos de datos).

Para que los contratos de datos sean equivalentes, deben incluir el mismo espacio de nombres y nombre. Además, cada miembro de datos en un lado debe tener un miembro de datos equivalente en el otro.

Para que los miembros de datos sean equivalentes, deben tener el mismo nombre. De manera adicional, deben representar el mismo tipo de datos; es decir, sus contratos de datos deben ser equivalentes.

Nota

Tenga en cuenta que los nombres y espacios de nombres de contrato de datos, así como los nombres del miembros de datos, distinguen entre mayúsculas y minúsculas.

Para más información sobre los nombres y los espacios de nombres de contrato de datos, así como los nombres de los miembros de datos, consulte Nombres de contratos de datos.

Si dos tipos existen en el mismo lado (remitente o receptor) y sus contratos de datos no son equivalentes (por ejemplo, tienen diferentes miembros de datos), no debería darles el mismo nombre y espacio de nombres. Si lo hace, pueden iniciarse excepciones.

Los contratos de datos de los tipos siguientes son equivalentes:

[DataContract]
public class Customer
{
    [DataMember]
    public string fullName;

    [DataMember]
    public string telephoneNumber;
}

[DataContract(Name = "Customer")]
public class Person
{
    [DataMember(Name = "fullName")]
    private string nameOfPerson;

    private string address;

    [DataMember(Name = "telephoneNumber")]
    private string phoneNumber;
}
<DataContract()> _
Public Class Customer

    <DataMember()> _
    Public fullName As String

    <DataMember()> _
    Public telephoneNumber As String
End Class

<DataContract(Name:="Customer")> _
Public Class Person

    <DataMember(Name:="fullName")> _
    Private nameOfPerson As String

    Private address As String

    <DataMember(Name:="telephoneNumber")> _
    Private phoneNumber As String
End Class

Orden del miembro de datos y equivalencia del contrato de datos

Utilizar la propiedad Order de la clase DataMemberAttribute puede afectar a la equivalencia del contrato de datos. Los contratos de datos deben tener miembros que aparecen en el mismo orden para ser equivalentes. El orden predeterminado es alfabético. Para más información, consulte Orden de los miembros de datos.

Por ejemplo, el código siguiente produce contratos de datos equivalentes.

[DataContract(Name = "Coordinates")]
public class Coords1
{
    [DataMember]
    public int X;
    [DataMember]
    public int Y;
    // Order is alphabetical (X,Y).
}

[DataContract(Name = "Coordinates")]
public class Coords2
{
    [DataMember]
    public int Y;
    [DataMember]
    public int X;
    // Order is alphabetical (X,Y), equivalent
    // to the preceding code.
}

[DataContract(Name = "Coordinates")]
public class Coords3
{
    [DataMember(Order = 2)]
    public int Y;
    [DataMember(Order = 1)]
    public int X;
    // Order is according to the Order property (X,Y),
    // equivalent to the preceding code.
}
<DataContract(Name:="Coordinates")> _
Public Class Coords1
    <DataMember()> _
    Public X As Integer
    <DataMember()> _
    Public Y As Integer
    ' Order is alphabetical (X,Y).
End Class

<DataContract(Name:="Coordinates")> _
Public Class Coords2

    <DataMember()> _
    Public Y As Integer
    <DataMember()> _
    Public X As Integer
    ' Order is alphabetical (X,Y), equivalent 
    ' to the preceding code.
End Class

<DataContract(Name:="Coordinates")> _
Public Class Coords3
    <DataMember(Order:=2)> _
    Public Y As Integer
    <DataMember(Order:=1)> _
    Public X As Integer
    ' Order is according to the Order property (X,Y), 
    ' equivalent to the preceding code.
End Class

Sin embargo, el siguiente código no produce un contrato de datos equivalente.

[DataContract(Name = "Coordinates")]
public class Coords4
{
    [DataMember(Order = 1)]
    public int Y;
    [DataMember(Order = 2)]
    public int X;
    // Order is according to the Order property (Y,X),
    // different from the preceding code.
}
<DataContract(Name:="Coordinates")> _
Public Class Coords4

    <DataMember(Order:=1)> _
    Public Y As Integer
    <DataMember(Order:=2)> _
    Public X As Integer
    ' Order is according to the Order property (Y,X), 
    ' different from the preceding code.
End Class

Herencia, interfaces y equivalencia del contrato de datos

Al determinar la equivalencia, un contrato de datos que hereda de otro contrato de datos se trata como si fuese, simplemente, un contrato de datos que incluye todos los miembros de datos del tipo base. Tenga presente que el orden de los miembros de datos debe coincidir y que los miembros de tipo base preceden, en el orden, a los miembros de tipo derivado. Además, si, como en el ejemplo de código siguiente, dos miembros de datos tienen el mismo valor de orden, la clasificación de esos miembros de datos será alfabética. Para más información, consulte Orden de los miembros de datos.

En el ejemplo siguiente, el contrato de datos para el tipo Employee es equivalente al contrato de datos para el tipo Worker.

[DataContract]
public class Person
{
    [DataMember]
    public string name;
}
[DataContract]
public class Employee : Person
{
    [DataMember]
    public int department;
    [DataMember]
    public string title;
    [DataMember]
    public int salary;
}
// Order is "name", "department", "salary", "title"
// (base class first, then alphabetical).

[DataContract(Name = "Employee")]
public class Worker
{
    [DataMember(Order = 1)]
    public string name;
    [DataMember(Order = 2)]
    public int department;
    [DataMember(Order = 2)]
    public string title;
    [DataMember(Order = 2)]
    public int salary;
}
// Order is "name", "department", "salary", "title"
// (Order=1 first, then Order=2 in alphabetical order),
// which is equivalent to the Employee order}.
<DataContract()> _
Public Class Person
    <DataMember()> Public name As String
End Class

<DataContract()> _
Public Class Employee
    Inherits Person
    <DataMember()> Public department As Integer
    <DataMember()> Public title As String
    <DataMember()> Public salary As Integer
End class

' Order is "name", "department", "salary", "title" 
' (base class first, then alphabetical).

<DataContract(Name:="Employee")> _
Public Class Worker

    <DataMember(Order:=1)> _
    Public name As String
    <DataMember(Order:=2)> _
    Public department As Integer
    <DataMember(Order:=2)> _
    Public title As String
    <DataMember(Order:=2)> _
    Public salary As Integer
End Class
' Order is "name", "department", "salary", "title" 
' (Order=1 first, then Order=2 in alphabetical order), 
' which is equivalent to the Employee order}.

Cuando se pasan parámetros y valores devueltos entre un cliente y un servicio, no se puede enviar un contrato de datos de una clase base si el punto de conexión receptor espera un contrato de datos de una clase derivada. Esto es conforme con los principios de la programación orientada a objetos. En el ejemplo anterior, no se puede enviar un objeto de tipo Person si se espera Employee.

Se puede enviar un contrato de datos de una clase derivada si se espera un contrato de datos de una clase base, pero solo si el punto de conexión receptor "conoce" el tipo derivado mediante KnownTypeAttribute. Para más información, consulte Tipos conocidos de contratos de datos. En el ejemplo anterior, se puede enviar un objeto de tipo Employee si se espera un Person, aunque solo si el código del receptor utiliza KnownTypeAttribute para incluirlo en la lista de tipos conocidos.

Al pasar parámetros y valores devueltos entre las aplicaciones, si el tipo esperado es una interfaz, es equivalente a cuando el tipo esperado es Object. Dado que, en última instancia, cada tipo deriva de Object, todos los contratos de datos derivan, a la larga, del contrato de datos para Object. De este modo, se puede pasar cualquier tipo de contrato de datos cuando se espera una interfaz. Son necesarios algunos pasos adicionales para trabajar correctamente con interfaces; para más información, consulte Tipos conocidos de contratos de datos.

Consulte también