Эквивалентность контрактов данных

Чтобы клиент мог успешно отправлять данные определенного типа службе или чтобы служба могла успешно отправлять данные клиенту, отправляемый тип не обязательно должен существовать на принимающей стороне. Единственное требование заключается в эквивалентности контрактов данных обоих типов. (В некоторых случаях, как описано в разделе о управлении версиями контракта данных, не требуется заключить в равенство.)

Чтобы контракты данных были эквивалентны, они должны иметь одинаковые пространство имен и имя. Кроме того, каждый член данных на одной стороне должен иметь эквивалентный член данных на другой стороне.

Чтобы члены данных были эквивалентны, они должны иметь одинаковое имя. Кроме того, они должны представлять один и тот же тип данных, т. е. их контракты данных должны быть эквивалентны.

Примечание

Обратите внимание, что в именах контрактов данных и пространствах имен, равно как и в именах членов данных, учитывается регистр.

Дополнительные сведения о именах контрактов данных и пространствах имен, а также об именах членов данных см. в разделе имена контрактов данных.

Если два типа существуют на одной и той же стороне (отправителя или получателя) и их контракты данных не эквивалентны (например, имеют разные члены данных), не следует давать им одно и то же имя и пространство имен. Это может привести к возникновению исключений.

Контракты данных для следующих типов эквивалентны:

[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

Эквивалентность порядка членов данных и контрактов данных

Использование свойства Order класса DataMemberAttribute может повлиять на эквивалентность контрактов данных. Чтобы контракты данных были эквивалентны, члены данных в них должны следовать в одинаковом порядке. По умолчанию они следуют в алфавитном порядке. Дополнительные сведения см. в разделе порядок элементов данных.

Например, следующий код представляет собой эквивалентные контракты данных.

[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

В то же время следующие примеры не являются эквивалентными контрактами данных.

[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

Наследование, интерфейсы и эквивалентность контрактов данных

При определении эквивалентности контракт данных, наследующий от других контрактов данных, рассматривается так, как будто это просто контракт данных, включающий все члены данных из базового типа. Следует помнить, что порядок членов данных должен совпадать, и что члены базового типа должны идти перед членами производного типа. Кроме того, если, как в следующем примере кода, два члена данных имеют одно и то же значение порядка, эти члены данных располагаются в алфавитном порядке. Дополнительные сведения см. в разделе порядок элементов данных.

В следующем примере контракт данных для типа Employee эквивалентен контракту данных для типа 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}.

При передаче параметров и возвращаемых значений между клиентом и службой нельзя отправить контракт данных от базового класса, когда принимающая конечная точка ожидает контракт данных от производного класса. Это соответствует принципам объектно-ориентированного программирования. В предыдущем примере объект типа Person не может быть отправлен, если Employee ожидается.

Можно отправить контракт данных от производного класса, когда ожидается контракт данных от базового класса, однако только при условии, что принимающая конечная точка "знает" производный тип путем использования атрибута KnownTypeAttribute. Дополнительные сведения см. в статье о известных типах контрактов данных. В предыдущем примере можно отправить объект типа Employee, если ожидается объект типа Person, однако только если в принимающем коде присутствует атрибут KnownTypeAttribute для включения этого типа в список известных типов.

Если при передаче параметров и возвращаемых значений между приложениями ожидаемый тип представляет собой интерфейс, это эквивалентно тому, что ожидаемый тип принадлежит к типу Object. Поскольку все типы в конечном итоге наследуются от Object, все контракты данных в конечном итоге наследуются от контракта данных для Object. Таким образом, когда ожидается интерфейс, передать можно любой контракт данных. Для успешной работы с интерфейсами требуются дополнительные действия. Дополнительные сведения см. в статье о известных типах контрактов данных.

См. также