数据协定等效性

要使客户端成功向服务发送特定类型的数据,或者向客户端成功发送数据的服务,则发送的类型不一定存在于接收端。 唯一的要求是这两种类型的数据协定是等效的。 (有时,不需要严格等价,如 数据协定版本控制中所述。

要使数据协定等效,它们必须具有相同的命名空间和名称。 此外,一端的每个数据成员必须在另一端具有等效的数据成员。

要使数据成员等效,它们必须具有相同的名称。 此外,它们必须表示相同类型的数据;也就是说,其数据协定必须等效。

注释

请注意,数据合同名称、命名空间和数据成员名称区分大小写。

有关数据协定名称和命名空间以及数据成员名称的详细信息,请参阅 数据协定名称

如果两种类型位于同一端(发送方或接收方),并且其数据协定不相等(例如,它们具有不同的数据成员),则不应为其提供相同的名称和命名空间。 否则,可能会引发异常。

以下类型的数据协定等效:

[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}.

在客户端和服务之间传递参数和返回值时,当接收终结点需要来自派生类的数据协定时,无法发送基类中的数据协定。 这符合面向对象的编程原则。 在前面的示例中,如果要求 Employee,则不能发送 Person 类型的对象。

如果要求来自基类的数据协定,则可发送来自派生类的数据协定,但前提是接收终结点通过 KnownTypeAttribute“知道”该派生类型。 有关详细信息,请参阅 数据协定已知类型。 在前面的示例中,当预期类型为Person时,可以发送类型为Employee的对象,但前提是接收方代码使用KnownTypeAttribute将其包含在已知类型列表中。

当应用程序之间传递参数和返回值时,如果预期类型是接口,则其等效于Object类型。 由于每种类型最终派生自Object,因此每个数据协定最终派生自Object的数据协定。 因此,当需要接口时,可以传递任何数据协定类型。 成功处理接口需要执行其他步骤;有关详细信息,请参阅 数据协定已知类型

另请参阅