【问题标题】:How to serialize & deserialize static reference object?如何序列化和反序列化静态引用对象?
【发布时间】:2026-01-01 19:20:05
【问题描述】:

我想使用 BinaryFormatter 序列化和反序列化一个对象(这个对象有引用)。

我预计 'DeserializedObject.Equals(A.Empty)' 与下面的代码相同。 但是,结果是不同的。

为了'DeserializedObject == A.Empty',如何使用序列化/反序列化?

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

【问题讨论】:

  • 您想在序列化/反序列化时保留对A 类实例的所有 引用,还是只保留对A.Empty 的引用?

标签: c# serialization binaryformatter


【解决方案1】:

原因是它们不同的对象!您可以通过打印他们的 GetHashCode() 来检查这一点。原因是在您的代码中:

  1. refObject 是对 A.Empty 的引用(因此是同一个对象)
  2. DeserializedObject 不是副本;它是一个新实例,所以 不同的对象

但是 DeserializedObject 应该包含相同的值(ID 和名称)。请注意,refObject.ID 将与 A.Empty.ID 是同一个对象; DeserialisedObject.ID 不会,尽管它应该包含相同的数据(副本)。

如果您只是测试反序列化是否有效,请测试 DeserializedObject 和 A.Empty 包含的值是否相同。

【讨论】:

  • 感谢您的回答,但我希望继续参考。 (refObject 是对 A.Empty 的引用)-------- Deserializing ------- DeserializedObject 是对 A.Empty 的引用。这个结果是不可能的?我希望在反序列化后保留对象引用。
  • 反序列化不是这样工作的。它总是会创建一个新对象——它真的不能以任何其他方式工作。
【解决方案2】:

如果您有一个不可变类型,它具有一个或多个表示该类型标准值的全局单例(在您的情况下为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);
        }
    }
}

【讨论】: