如何序列化&反序列化静态引用对象
本文关键字:静态 引用 对象 反序列化 序列化 | 更新日期: 2023-09-27 18:11:12
我要序列化&使用BinaryFormatter反序列化一个对象(该对象有引用)。
我期望' deserializedoobject . equals (A.Empty)'与下面的代码相同。但是,结果是不同的。
为了` DeserializedObject == A.Empty `,如何使用serialize/deserialize ?
[Serializable]
public class A
{
private string ID = null;
private string Name = null;
public A()
{ }
public static A Empty = new A()
{
ID = "Empty",
Name = "Empty"
};
}
class Program
{
static void Main(string[] args)
{
A refObject = A.Empty; // Add reference with static object(Empty)
A DeserializedObject;
//Test
//before serialization, refObject and A.Empty is Same!!
if(refObject.Equals(A.Empty))
{
Console.WriteLine("refObject and A.Empty is the same ");
}
//serialization
using (Stream stream = File.Create("C:''Users''admin''Desktop''test.mbf"))
{
BinaryFormatter bin = new BinaryFormatter();
bin.Serialize(stream, refObject);
}
//Deserialization
using (Stream stream = File.Open("C:''Users''admin''Desktop''test.mbf", FileMode.Open))
{
BinaryFormatter bin = new BinaryFormatter();
DeserializedObject = (A)bin.Deserialize(stream);
}
//compare DeserializedObject and A.Empty again.
//After deserialization, DeserializedObject and A.Empty is Different!!
if (DeserializedObject.Equals(A.Empty))
{
Console.WriteLine("Same");
}
else
Console.WriteLine("Different");
}
}
原因是它们是不同的对象!你可以通过打印它们的GetHashCode()来检查这一点。这样做的原因是在您的代码中:
- refObject是a . empty的引用(因此是同一个对象)
- DeserialisedObject不是一个副本;这是一个新实例,所以不同的对象
但是DeserializedObject应该包含相同的值(ID和Name)。注意refObject。ID将是与A.Empty.ID相同的对象;DeserialisedObject。ID不会,尽管它应该包含相同数据的(副本)。
如果你只是在测试反序列化是否有效,测试DeserializedObject和A.Empty包含的值是否相同
如果你有一个不可变类型,它有一个或多个表示该类型的标准值的全局单例(在你的例子中是A.Empty
),你可以实现IObjectReference
接口,并使BinaryFormatter
用适当的,等效的全局单例替换该类型的反序列化实例。因此:
[Serializable]
public class A : IObjectReference
{
private string ID = null;
private string Name = null;
public A()
{ }
public static A Empty = new A()
{
ID = "Empty",
Name = "Empty"
};
#region IObjectReference Members
object IObjectReference.GetRealObject(StreamingContext context)
{
if (this.GetType() == Empty.GetType() // Type check because A is not sealed
&& this.ID == Empty.ID
&& this.Name == Empty.Name)
return Empty;
return this;
}
#endregion
}
和,测试:
public class TestClass
{
public static void Test()
{
A refObject = A.Empty; // Add reference with static object(Empty)
Test(refObject, true);
A dummy = new A(); // No global singleton for this one.
Test(dummy, false);
}
private static void Test(A refObject, bool shouldBeEqual)
{
Console.WriteLine(string.Format("refObject and A.Empty are {0}.", object.ReferenceEquals(refObject, A.Empty) ? "identical" : "different"));
var binary = BinaryFormatterHelper.ToBase64String(refObject);
var DeserializedObject = BinaryFormatterHelper.FromBase64String<A>(binary);
Console.WriteLine(string.Format("DeserializedObject and A.Empty are {0}.", object.ReferenceEquals(DeserializedObject, A.Empty) ? "identical" : "different"));
Debug.Assert(object.ReferenceEquals(refObject, A.Empty) == object.ReferenceEquals(DeserializedObject, A.Empty)); // No assert
Debug.Assert(shouldBeEqual == object.ReferenceEquals(refObject, DeserializedObject)); // No assert
}
}
public static class BinaryFormatterHelper
{
public static string ToBase64String<T>(T obj)
{
using (var stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, obj);
return Convert.ToBase64String(stream.GetBuffer(), 0, checked((int)stream.Length)); // Throw an exception on overflow.
}
}
public static T FromBase64String<T>(string data)
{
return FromBase64String<T>(data, null);
}
public static T FromBase64String<T>(string data, BinaryFormatter formatter)
{
using (var stream = new MemoryStream(Convert.FromBase64String(data)))
{
formatter = (formatter ?? new BinaryFormatter());
var obj = formatter.Deserialize(stream);
if (obj is T)
return (T)obj;
return default(T);
}
}
}