对象序列化之 替换(Surrogate)
有可能存在一种情况,实体类型无法进行序列化或需要在序列化的方式上进行更改,如 第三方组件供应商提供的类型或者没有源代码的组件。 对于这种情况,WCF提供IDataContractSurrogate 接口 来实现一个替身类解决此类问题。
解决问题的步骤:
1. 定义数据契约来表示序列化的类型;
2. 定义实现序列化替身的操作类,实现IDataContractSurrogate接口,并至少实现其三个方法: GetDataContractType、GetDeserializedObject、GetObjectToSerialize ,其中GetDataContractType方法会向DataContractSerializer 返回需要序列化的类型,而GetObjectToSerialize和GetDeserializedObject会实际执行序列化和反序列化。
以下代码:
假设 Employee 无法实现序列化,以EmployeeSurrogated 作为其替身类,以EmpoyyeeSurrogate实现操作,代码如下:
EmployeeSurrogated 定义:
[DataContract] internal class EmployeeSurrogated { public EmployeeSurrogated(int employeeID, string firstName, string lastName) { this.employeeID = employeeID; this.firstName = firstName; this.lastName = lastName; } [DataMember] private int employeeID; [DataMember] private string firstName; [DataMember] private string lastName; public int EmployeeID { get { return this.employeeID; } } public string FirstName { get { return this.firstName; } } public string LastName { get { return this.lastName; } } }
EmployeeSurrogate 操作类:
public class EmployeeSurrogate : IDataContractSurrogate { public object GetCustomDataToExport(Type clrType, Type dataContractType) { return null; } public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType) { return null; } /// <summary> /// 向DataContractSerializer 返回需要序列化的类型 /// </summary> /// <param name="type"></param> /// <returns></returns> public Type GetDataContractType(Type type) { if (typeof(Employee).IsAssignableFrom(type)) { return typeof(EmployeeSurrogated); } return type; } /// <summary> /// 执行反序列化后应返回的实际类型 /// </summary> /// <param name="obj"></param> /// <param name="targetType"></param> /// <returns></returns> public object GetDeserializedObject(object obj, Type targetType) { if (obj is EmployeeSurrogated) { EmployeeSurrogated oldEmployee = obj as EmployeeSurrogated; Employee newEmployee = new Employee() { EmployeeID = oldEmployee.EmployeeID, FirstName = oldEmployee.FirstName, LastName = oldEmployee.LastName }; return newEmployee; } return obj; } public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes) { throw new NotImplementedException(); } /// <summary> /// 将无法序列化的对象转化会替身类性 /// </summary> /// <param name="obj"></param> /// <param name="targetType"></param> /// <returns></returns> public object GetObjectToSerialize(object obj, Type targetType) { if (obj is Employee) { Employee oldEmployee = obj as Employee; EmployeeSurrogated newEmployee = new EmployeeSurrogated(oldEmployee.EmployeeID, oldEmployee.FirstName, oldEmployee.LastName); return newEmployee; } return obj; } public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) { if (typeNamespace.Equals(@"http://schemas.datacontract.org/2004/07/EmplyeeSurrogated")) { if (typeName.Equals("EmployeeSurrogated")) { return typeof(Employee); } } return null; } public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit) { return typeDeclaration; } }
序列化方式:
序列化器: 注意 DataContractSerializer 的实例化调用的构造方法,此关键操作导致可以实现替代的序列化;
public static string TryToSerialize(object obj) { DataContractSerializer serializer = new DataContractSerializer(obj.GetType()); using (StringWriter strWriter = new StringWriter()) { using (XmlWriter xWriter = XmlWriter.Create(strWriter)) { try { serializer.WriteObject(xWriter, obj); xWriter.Flush(); return strWriter.ToString(); } catch (Exception ex) { Console.WriteLine("Can not serialize without a surrogate : {0}", ex); } } } return string.Empty; } public static string SerializeUsingSurrogate(object obj, IDataContractSurrogate surrogateObj) { DataContractSerializer serializer = new DataContractSerializer(obj.GetType(), null, int.MaxValue, false, false, surrogateObj); return SerializeUsingSurrogate(serializer, obj); } public static string SerializeUsingSurrogate(DataContractSerializer serializer, object obj) { using (StringWriter strWriter = new StringWriter()) { using (XmlWriter xWriter = XmlWriter.Create(strWriter)) { serializer.WriteObject(xWriter, obj); xWriter.Flush(); return strWriter.ToString(); } } } public static object DeserializeUsingSurrogate(Type sourceType, IDataContractSurrogate surrogateObj, string objXml) { DataContractSerializer serializer = new DataContractSerializer(sourceType, null, int.MaxValue, false, false, surrogateObj); return DeserializeUsingSurrogate(serializer, objXml); } public static object DeserializeUsingSurrogate(DataContractSerializer serializer, string objXml) { using (StringReader strReader = new StringReader(objXml)) { using (XmlReader xReader = XmlReader.Create(strReader)) { return serializer.ReadObject(xReader); } } }
最后执行:
static void SerializeSurrogate() { Employee e = new Employee() { EmployeeID = 1, FirstName = "jerry", LastName = "shi" }; Console.WriteLine("{0},{1},{2}", e.EmployeeID, e.FirstName, e.LastName); SerializeHelper.TryToSerialize(e); string objXml = SerializeHelper.SerializeUsingSurrogate(e, new EmployeeSurrogate()); Console.WriteLine(objXml); Employee newobj = (Employee)SerializeHelper.DeserializeUsingSurrogate(e.GetType(), new EmployeeSurrogate(), objXml); Console.WriteLine("{0},{1},{2}", newobj.EmployeeID, newobj.FirstName, newobj.LastName); Console.WriteLine("Press <Enter> to continute..."); Console.ReadLine(); }
结果说明: