How to serialize & deserialize static reference object?

半世苍凉 提交于 2019-12-13 04:10:51

问题


i want to serialize & deserialize a object (this object has reference) using BinaryFormatter.

i have expected that 'DeserializedObject.Equals(A.Empty)' is same to below code. but, a result is different.

in order to 'DeserializedObject == A.Empty', how to use 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");
    }
}

回答1:


The reason for this is that they are different objects! You can check this by printing their GetHashCode(). The reason for this is that in your code:

  1. refObject is a reference to A.Empty (and thus the same object)
  2. DeserialisedObject is NOT a copy; it is a new instance and so a different object

However DeserializedObject should contain the same values (ID and Name). Note that refObject.ID will be the same object as A.Empty.ID; DeserialisedObject.ID will not, although is should contain (a copy of) the same data.

If you're just testing that deserialization is working, test that the values contained by DeserializedObject and A.Empty are the same.




回答2:


If you have an immutable type which has one or more global singletons that represent standard values of the type (A.Empty in your case), you can implement the IObjectReference interface and make BinaryFormatter replace deserialized instances of the type with the appropriate, equivalent global singleton. Thus:

[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
}

And, to test:

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);
        }
    }
}


来源:https://stackoverflow.com/questions/32375207/how-to-serialize-deserialize-static-reference-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!