序列化同一个对象会产生不同的流吗?

时间:2011-10-31 13:17:43

标签: .net serialization

在序列化同一个对象时是否会产生不同的流(假设其中一个内置的.NET格式化程序用于两个序列化)?

这在以下this post的讨论中提出。有人声称这可能发生,但没有提供具体的解释,所以我想知道是否有人可以解释这个问题?

3 个答案:

答案 0 :(得分:6)

正如我在SO问题的评论中所解释的那样,通过优化字符串输出引起问题(至少我发现的情况)。 看起来如果字符串是相同的引用,那么它将输出一次。

那么我们的示例代码是如何使用长字符串来表示对象的属性并更改一个字符串的引用然后序列化。然后将流再次反序列化为对象(这次是因为字符串被实现,使用相同的引用)然后再次序列化。这次流更小

好的,这是证明代码:

[Serializable]
public class Proof
{
    public string S1 { get; set; }
    public string S2 { get; set; }
    public string S3 { get; set; }
}

class Program
{
    static void Main(string[] args)
    {

        const string LongString =
            "A value that is going to change the world nad iasjdsioajdsadj sai sioadj sioadj siopajsa iopsja iosadio jsadiojasd ";

        var proof = new Proof() {
            S1 = LongString,
            S2 = LongString,
            S3 = LongString
        };

        proof.S2 = LongString.Substring(0, 10) + LongString.Substring(10); // just add up first 10 character with the rest. 
               //This just makes sure reference is not the same although values will be

        Console.WriteLine(proof.S1 == proof.S2);
        Console.WriteLine(proof.S1 == proof.S3);
        Console.WriteLine(proof.S2 == proof.S3);
        Console.WriteLine("So the values are all the same...");

        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream stream = new MemoryStream();
        bf.Serialize(stream, proof);
        byte[] buffer = stream.ToArray();
        Console.WriteLine("buffer length is " + buffer.Length); // outputs 449 on my machine
        stream.Position = 0;
        var deserProof = (Proof) bf.Deserialize(new MemoryStream(buffer));
        deserProof.S1 = deserProof.S2;
        deserProof.S3 = deserProof.S2;
        MemoryStream stream2 = new MemoryStream();
        new BinaryFormatter().Serialize(stream2, deserProof);

        Console.WriteLine("buffer length now is " + stream2.ToArray().Length); // outputs 333 on my machine!!
        Console.WriteLine("What? I cannot believe my eyes! Someone help me ........");

        Console.Read();
    }

答案 1 :(得分:3)

某些核心类型(DateTime - 特别注意“种类”或Decimal注意到比例)可能会将报告的值相等,但序列化的方式不同;例如:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
class Foo
{
    public decimal Bar { get; set; }
    static void Main()
    {
        Foo foo = new Foo();
        foo.Bar = 123.45M;
        var s = Serialize(foo);

        Foo foo2 = new Foo();
        foo2.Bar = 123.4500M;

        bool areSame = foo.Bar == foo2.Bar; // true
        var s2 = Serialize(foo2);

        bool areSerializedTheSame = s == s2; // false
    }
    static string Serialize(object obj)
    {
        using (var ms = new MemoryStream())
        {
            new BinaryFormatter().Serialize(ms, obj);
            return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
        }
    }
}

关于 exact 同一个对象是否可以进行不同的序列化 - 好吧,这通常不能保证序列化可以做出任何声明。序列化是关于存储和检索数据/对象 - 关于证明相等性。例如,xml具有各种空格和名称空间规范化问题,使其不适合进行比较。 BinaryFormatter和其他二进制序列化程序看起来更有诱惑力,但我不确定它们是否能保证您正在寻找的行为。

除非序列化程序明确做出此保证,否则我不会完全相信通过这种方法进行的比较。

答案 2 :(得分:1)

取决于您所谓的“相同”对象。

但是,是的,2个实例可以比较为Equal = true并且仍然会产生不同的流。

  • 非常简单地使用Equals的破坏或限制覆盖
  • 因为归一化或操作顺序引起的细微差别。

我确认以不同的顺序向Dictionary添加相同的元素会产生不同的流。我假设您会考虑2个具有相同内容“相等”的词典。