Equivalenza dei contratti dati

Perché un client possa inviare correttamente dati di un certo tipo a un servizio o perché un servizio possa inviare correttamente dati a un client, non è necessario che il tipo inviato sia presente nell'estremità ricevente. L'unico requisito è che i contratti dati di entrambi i tipi siano equivalenti. A volte non è necessaria una rigorosa equivalenza, come illustrato in Controllo delle versioni del contratto dati.

Perché i contratti dati siano equivalenti devono avere lo stesso spazio dei nomi e lo stesso nome. Ogni membro dati su uno lato deve inoltre avere un membro dati equivalente sull'altro lato.

Perché i membri dati siano equivalenti devono avere lo stesso nome. Devono inoltre rappresentare lo stesso tipo di dati, che significa che i rispettivi contratti dati devono essere equivalenti.

Nota

Sia per i nomi e gli spazi dei nomi dei contratti dati sia per i nomi dei membri dati viene fatta distinzione tra maiuscole e minuscole.

Per altre informazioni sui nomi e sugli spazi dei nomi dei contratti dati, nonché sui nomi dei membri dati, vedere Nomi dei contratti dati.

Se sullo stesso lato (mittente o ricevitore) sono presenti due tipi e i contratti dati non sono equivalenti (ad esempio, hanno membri dati diversi), è necessario assegnare loro un nome e uno spazio dei nomi differenti. In caso contrario, è possibile che vengano generate eccezioni.

I contratti dati per i tipi seguenti sono equivalenti:

[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

Ordine dei membri dati ed equivalenza dei contratti dati

L'utilizzo della proprietà Order della classe DataMemberAttribute può influire sull'equivalenza dei contratti dati. Per essere equivalenti, i contratti dati devono avere membri disposti nello stesso ordine. L'ordine predefinito è quello alfabetico. Per altre informazioni, vedere Ordine dei membri dati.

Il codice seguente, ad esempio, comporta contratti dati equivalenti.

[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

Il codice seguente non comporta invece contratti dati equivalenti.

[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

Ereditarietà, interfacce ed equivalenza dei contratti dati

Quando viene determinata l'equivalenza, un contratto dati che eredita da un altro contratto dati viene trattato come se fosse un contratto dati che include tutti i membri dati del tipo di base. Tenere presente che l'ordine dei membri dati deve corrispondere e che i membri del tipo di base precedono nell'ordine i membri del tipo derivato. Inoltre, se due membri dati hanno lo stesso valore di ordine, come nell'esempio di codice seguente, l'ordinamento di questi membri dati è alfabetico. Per altre informazioni, vedere Ordine dei membri dati.

Nell'esempio seguente il contratto dati per il tipo Employee è equivalente al contratto dati per il 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}.

Quando vengono passati parametri e restituiti valori tra un client e un servizio, non è possibile inviare un contratto dati relativo a una classe di base se l'endpoint ricevente prevede un contratto dati relativo a una classe derivata. Questo comportamento è conforme ai principi di base della programmazione orientata a oggetti. Nell'esempio precedente non è possibile inviare un oggetto di tipo Person se è previsto un oggetto di tipo Employee.

Un contratto dati relativo a una classe derivata può essere inviato quando è previsto un contratto dati relativo a una classe di base soltanto se l'endpoint ricevente "riconosce" il tipo derivato usando la classe KnownTypeAttribute. Per altre informazioni, vedere Tipi noti del contratto dati. Nell'esempio precedente un oggetto di tipo Employee può essere inviato se è previsto un oggetto di tipo Person, ma solo se il codice del ricevitore usa la classe KnownTypeAttribute per includerlo nell'elenco dei tipi noti.

Quando vengono passati parametri e restituiti valori tra applicazioni, se il tipo previsto è un'interfaccia è come se fosse di tipo Object. Poiché ogni tipo deriva in fondo da Object, ogni contratto dati deriva in ultima istanza dal contratto dati relativo a Object. Quando è prevista un'interfaccia è pertanto possibile passare qualsiasi tipo di contratto dati. Per usare correttamente le interfacce sono necessari ulteriori passaggi. Per altre informazioni, vedere Tipi conosciuti di contratto dati.

Vedi anche