C# 序列化过程中的已知类型(Known Type)
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
- 上一篇:C#.NET里面抽象类,接口,虚方法
- 下一篇:Winform开发之窗体传值