当前位置:首页 > Windows程序 > 正文

C# 序列化过程中的已知类型(Known Type)

2021-05-24 Windows程序

WCF下的序列化与反序列化解决的是数据在两种状态之间的相互转化:托管类型对象和XML。由于类型定义了对象的数据结构,所以无论对于序列化还是反序列化,都必须事先确定对象的类型。如果被序列化对象或者被反序列化生成的对象包含不可知的类型,序列化或者反序列化将会失败。为了确保DataContractSerializer的正常序列化和反序列化,我们需要将“未知”类型加入DataContractSerializer“已知”类型列表中。

一、未知类型导致序列化失败

.NET的类型可以分为两种:声明类型和真实类型。我们提倡面向接口的编程,对象的真实类型往往需要在运行时才能确定,在编程的时候往往只需要指明类型的声明类型,比如类型实现的接口或者抽象类。当我们使用基于接口或者抽象类创建的DataContractSerializer去序列化一个实现了该接口或者继承该抽象类的实例的时候,往往会因为对对象的真实类型无法识别造成不能正常地序列化。比如下面的代码中,我们定义了3个类型,一个接口、一个抽象类和一个具体类。

1: namespace Artech.DataContractSerializerDemos 2: { 3: public interface IOrder 4: { 5: Guid ID 6: { get; set; } 7:  8: DateTime Date 9: { get; set; } 10:  11: string Customer 12: { get; set; } 13:  14: string ShipAddress 15: { get; set; } 16: } 17:  18: [DataContract] 19: public abstract class OrderBase : IOrder 20: { 21: [DataMember] 22: public Guid ID 23: { get; set; } 24:  25: [DataMember] 26: public DateTime Date 27: { get; set; } 28:  29: [DataMember] 30: public string Customer 31: { get; set; } 32:  33: [DataMember] 34: public string ShipAddress 35: { get; set; } 36: } 37:  38: [DataContract] 39: public class Order : OrderBase 40: { 41: [DataMember] 42: public double TotalPrice 43: { get; set; } 44: } 45: }

当我们通过下面的方式去序列化一个Order对象(注意泛型类型为IOrder或者OrderBase),将会抛出如图1所示SerializationException异常,提示Order类型无法识别。

注:Serialize<T>方法的定义,请参考本系列的上篇文章:《WCF技术剖析之十二:数据契约(Data Contract)和数据契约序列化器(DataContractSerializer)》。

1: Order order = new Order() 2: { 3: ID = Guid.NewGuid(), 4: Customer = "NCS", 5: Date = DateTime.Today, 6: ShipAddress = "#328, Airport Rd, Industrial Park, Suzhou Jiangsu Province", 7: TotalPrice = 8888.88 8: }; 9:  10: Serialize<IOrder>(order, @"E:\order.xml"); 11: //或者 12: Serialize<OrderBase>(order, @"E:\order.xml");

技术分享

图1 “未知”类型导致的序列化异常

二、DataContractSerializer的已知类型集合

解决上面这个问题的唯一途径就是让DataContractSerializer能够识别Order类型,成为DataContractSerializer的已知类型(Known Type)。DataContractSerializer内部具有一个已知类型的列表,我们只需要将Order的类型添加到这个列表中,就能从根本上解决这个问题。通过下面6个重载构造函数中的任意一个,均可以通过knownTypes参数指定DataContractSerializer的已知类型集合,该集合最终反映在DataContractSerializer的制度属性KnownTypes上。

1: public sealed class DataContractSerializer : XmlObjectSerializer 2: { 3: public DataContractSerializer(Type type, IEnumerable<Type> knownTypes); 4: public DataContractSerializer(Type type, string rootName, string rootNamespace, IEnumerable<Type> knownTypes); 5: public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace, IEnumerable<Type> knownTypes); 6: public DataContractSerializer(Type type, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences, IDataContractSurrogate dataContractSurrogate); 7: public DataContractSerializer(Type type, string rootName, string rootNamespace, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences, IDataContractSurrogate dataContractSurrogate); 8: public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences, IDataContractSurrogate dataContractSurrogate); 9: 10: public ReadOnlyCollection<Type> KnownTypes { get; } 11: }

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/70223.html