对象序列化之 替换(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();
        }

结果说明:

序列化替代结果

 

posted @ 2011-11-19 00:28  JerryShi  阅读(517)  评论(0编辑  收藏  举报