数据协定已知类型

KnownTypeAttribute 类允许您预先指定应该在反序列化期间包括在考虑范围内的类型。有关工作示例,请参见Known Types示例。

通常,在客户端和服务之间传递参数和返回值时,这两个终结点共享要传输的数据的所有数据协定。但是,在以下情况下并非如此:

  • 已发送的数据协定源自预期的数据协定(有关更多信息,请参见 数据协定等效性中有关继承的一节)。在该情况下,传输的数据没有与接收终结点所预期相同的数据协定。
  • 要传输的信息的声明类型是接口,而非类、结构或枚举。因此,无法预先知道实际发送了实现接口的哪个类型,接收终结点就无法预先确定已传输数据的数据协定。
  • 要传输的信息的声明类型是 Object。由于每个类型都继承自 Object,而且无法预先知道实际发送了哪个类型,因此接收终结点无法预先确定已传输数据的数据协定。这是第一个项的特殊情况:每个数据协定都源自为 Object 生成的默认空数据协定。
  • 某些类型(包括 .NET Framework 类型)具有上述三种类别之一中的成员。例如,Hashtable 使用 Object 在哈希表中存储实际对象。在序列化这些类型时,接收方无法预先确定这些成员的数据协定。

KnownTypeAttribute 类

在数据到达接收终结点时,WCF 运行库尝试将数据反序列化为公共语言运行库 (CLR) 类型的实例。通过首先检查传入消息选择为反序列化而实例化的类型,以确定消息内容遵循的数据协定。然后反序列化引擎尝试查找实现与消息内容兼容的数据协定的 CLR 类型。反序列化引擎在此过程中允许的侯选类型集称为反序列化程序的“已知类型”集。

让反序列化引擎了解某个类型的一种方法是使用 KnownTypeAttribute。不能将属性应用于单个数据成员,只能将它应用于整个数据协定类型。将属性应用于可能为类或结构的“外部类型”**。在其最基本的用法中,应用属性会将类型指定为“已知类型”。只要反序列化外部类型的对象或通过其成员引用的任何对象,这就会导致已知类型成为已知类型集的一部分。可以将多个 KnownTypeAttribute 属性应用于同一类型。

已知类型和基元

基元类型以及被视为基元的某些类型(例如,DateTimeXmlElement)始终是“已知”的,且从来不必通过此机制进行添加。但是,必须显式添加基元类型的数组。大多数集合被视为等效于数组。(非泛型集合被视为等效于 Object 的数组)。有关使用基元、基元数组和基元集合的示例,请参见示例 4。

提示

与其他基元类型不同,DateTimeOffset 结构默认情况下不是已知类型,因此必须将它手动添加到已知类型列表。

示例

下面的示例说明如何使用 KnownTypeAttribute 类。

示例 1

有三个具有继承关系的类。

如果 ShapeOfLogo 成员设置为 CircleTypeTriangleType 对象,则可以序列化下面的 CompanyLogo 类,而不能对其进行反序列化,因为反序列化引擎无法识别具有数据协定名称“Circle”或“Triangle”的任何类型。

在下面的代码中演示了编写 CompanyLogo 类型的正确方法。

只要反序列化外部类型 CompanyLogo2,反序列化引擎就会了解有关 CircleTypeTriangleType,因此能够查找“Circle”和“Triangle”数据协定的匹配类型。

示例 2

在下面的示例中,尽管 CustomerTypeACustomerTypeB 都具有 Customer 数据协定,但是只要反序列化 PurchaseOrder 就会创建 CustomerTypeB 的实例,因为只有 CustomerTypeB 对反序列化引擎是已知的。

示例 3

在下面的示例中,Hashtable 将其内容在内部存储为 Object。若要成功反序列化哈希表,反序列化引擎必须知道那里可能出现的一组可能类型。在这种情况下,我们预先知道只有 BookMagazine 对象存储在 Catalog 中,因此使用 KnownTypeAttribute 属性添加它们。

示例 4

在下面的示例中,数据协定存储一个数字和要对该数字执行的操作。Numbers 数据成员可以是整数、整数数组或包含整数的 List

这是应用程序代码。

已知类型、继承和接口

使用 KnownTypeAttribute 属性将已知类型与特定类型关联时,已知类型也与该类型的所有派生类型关联。例如,请参见下面的代码。

DoubleDrawing 类无需 KnownTypeAttribute 属性即可在 AdditionalShape 字段中使用 SquareCircle,因为基类 (Drawing) 已经应用这些属性。

已知类型只能与类和结构关联,而不能与接口关联。

使用开放式泛型方法的已知类型

可能需要将泛型类型作为已知类型添加。但是,不能将开放式泛型类型作为参数传递到 KnownTypeAttribute 属性。

通过使用替代机制可以解决此问题:编写一个返回要添加到已知类型集合的类型列表的方法。然后将方法名称指定为 KnownTypeAttribute 属性的字符串参数(由于某些限制所致)。

方法必须存在于应用 KnownTypeAttribute 属性的类型上,不得接受参数,且必须返回可以分配给 TypeIEnumerable 的对象。

不能将具有方法名称的 KnownTypeAttribute 属性与实际类型在同一类型上的 KnownTypeAttribute 属性组合在一起。此外,不能将具有方法名称的多个 KnownTypeAttribute 应用于同一类型。

请参见下面的类。

theDrawing 字段包含泛型类 ColorDrawing 和泛型类 BlackAndWhiteDrawing 的实例,这两个泛型类都是从泛型类 Drawing 继承的。通常,必须将它们添加到已知类型,但下面不是有效的属性语法。

// 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)))>

因此,必须创建一个方法以返回这些类型。在下面的代码中演示了编写此类型的正确方法。

添加已知类型的其他方法

也可以将类型添加到通过 DataContractSerializerKnownTypes 属性访问的 ReadOnlyCollection

此外,可以通过配置文件添加已知类型。在不控制需要已知类型才能正确反序列化的类型时,这是很有用的,如将第三方类型库与 Windows Communication Foundation (WCF) 一起使用时。

下面的配置文件演示如何在配置文件中指定已知类型。

<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>

在前面的配置文件中,名为 MyCompany.Library.Shape 的数据协定类型被声明具有已知类型 MyCompany.Library.Circle

另请参见

参考

KnownTypeAttribute
Hashtable
Object
DataContractSerializer
KnownTypes

概念

数据协定等效性

其他资源

Known Types