建议57:实现ISerializable的子类型应负责父类的序列化
我们将要实现的继承自ISerializable的类型Employee有一个父类Person,假设Person没有实现序列化,而现在子类Employee却需要满足序列化的场景。不过序列化器并没有默认处理Person类型对象,这些事情只能由我们自己做。
以下是一个不妥的实现,序列化器只发现和处理了Employee中Salary字段:
classPRogram
{staticvoidMain()
{
Employee liming=newEmployee() { Name ="liming", Salary =2000};
BinarySerializer.SerializeToFile(liming,@"c:\","person.txt");
Employee limingCopy= BinarySerializer.DeserializeFromFile<Employee>(@"c:\person.txt");
Console.WriteLine(string.Format("姓名:{0}", limingCopy.Name));
Console.WriteLine(string.Format("薪水:{0}", limingCopy.Salary));
}
}publicclassPerson
{publicstringName {get;set; }
}
[Serializable]publicclassEmployee : Person, ISerializable
{publicintSalary {get;set; }publicEmployee()
{
}protectedEmployee(SerializationInfo info, StreamingContext context)
{
Salary= info.GetInt32("Salary");
}publicoverridevoidGetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Salary", Salary);
}
}
序列化工具类:
[flash=500,400]http://s1.knowsky.com/20160211/5ovxhdqzbzb49.gif[/flash][flash=500,400]http://s1.knowsky.com/20160211/mlnlqzwmkif49.gif[/flash]publicclassBinarySerializer
{//将类型序列化为字符串publicstaticstringSerialize<T>(T t)
{using(MemoryStream stream =newMemoryStream())
{
BinaryFormatter formatter=newBinaryFormatter();
formatter.Serialize(stream, t);returnSystem.Text.Encoding.UTF8.GetString(stream.ToArray());
}
}//将类型序列化为文件publicstaticvoidSerializeToFile<T>(T t,stringpath,stringfullName)
{if(!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}stringfullPath =Path.Combine(path, fullName);using(FileStream stream =newFileStream(fullPath, FileMode.OpenOrCreate))
{
BinaryFormatter formatter=newBinaryFormatter();
formatter.Serialize(stream, t);
stream.Flush();
}
}//将字符串反序列化为类型publicstaticTResult Deserialize<TResult>(strings)whereTResult :class{byte[] bs =System.Text.Encoding.UTF8.GetBytes(s);using(MemoryStream stream =newMemoryStream(bs))
{
BinaryFormatter formatter=newBinaryFormatter();returnformatter.Deserialize(stream)asTResult;
}
}//将文件反序列化为类型publicstaticTResult DeserializeFromFile<TResult>(stringpath)whereTResult :class{using(FileStream stream =newFileStream(path, FileMode.Open))
{
BinaryFormatter formatter=newBinaryFormatter();returnformatter.Deserialize(stream)asTResult;
}
}
}
View Code
输出为:
姓名:
薪水:2000
看见,Name字段并没有正确处理。这需要我们修改类型Employee中受保护的构造方法GetObjectData方法,为它加入父类字段的处理:
[Serializable]publicclassEmployee : Person, ISerializable
{publicintSalary {get;set; }publicEmployee()
{
}protectedEmployee(SerializationInfo info, StreamingContext context)
{
Name= info.GetString("Name");
Salary= info.GetInt32("Salary");
}publicvoidGetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Name", Name);
info.AddValue("Salary", Salary);
}
}
修改后输出:
姓名:liming
薪水:2000
上面的例子中Person类未被设置成支持序列化。现在,假设Person类已经实现了ISerializable接口,那么这个问题处理起来会相对容易,在子类Employee中,我们只需要调用父类受保护的构造方法和GetObjectData方法就可以了。如下所示:
[Serializable]publicclassPerson : ISerializable
{publicstringName {get;set; }publicPerson()
{
}protectedPerson(SerializationInfo info, StreamingContext context)
{
Name= info.GetString("Name");
}publicvirtualvoidGetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Name", Name);
}
}
[Serializable]publicclassEmployee : Person, ISerializable
{publicintSalary {get;set; }publicEmployee()
{
}protectedEmployee(SerializationInfo info, StreamingContext context)
:base(info, context)
{
Salary= info.GetInt32("Salary");
}publicoverridevoidGetObjectData(SerializationInfo info, StreamingContext context)
{base.GetObjectData(info, context);
info.AddValue("Salary", Salary);
}
}
转自:《编写高质量代码改善C#程序的157个建议》陆敏技