Может ли сериализация одного и того же объекта создавать разные потоки? - PullRequest
5 голосов
/ 31 октября 2011

Существует ли ситуация, когда при сериализации одного и того же объекта могут создаваться разные потоки (при условии, что для обеих сериализаций используется один из встроенных форматеров .NET)?

Это обсуждалось ниже этот пост .Было заявлено, что это может произойти, но никаких конкретных объяснений не было, поэтому мне было интересно, сможет ли кто-нибудь пролить свет на этот вопрос?

Ответы [ 3 ]

6 голосов
/ 31 октября 2011

Как я объяснил в комментарии к этому вопросу 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();
    }
3 голосов
/ 31 октября 2011

Некоторые основные типы (DateTime - отмечая, в частности, "kind" или 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);
        }
    }
}

Относительно того, может ли точный один и тот же объект сериализоваться по-разному - ну, обычно это не гарантия того, что сериализация делает какие-либо претензии. Сериализация - это хранение и извлечение ваших данных / объектов - , а не о доказательстве равенства. Например, xml имеет все виды проблем нормализации пробелов и пространств имен, которые делают его непригодным для сравнения. BinaryFormatter и другие двоичные сериализаторы выглядят более заманчиво, но я не уверен, что они гарантируют поведение, которое вы ищете.

Я бы не стал доверять сравнению, выполненному с помощью такого подхода, если бы сериализатор явно не сделал эту гарантию.

1 голос
/ 31 октября 2011

Немного зависит от того, что вы называете «тем же» объектом.

Но да, 2 экземпляра могут сравниваться как Equal = true и по-прежнему создавать разные потоки.

  • очень тривиально со сломанным или ограниченным переопределением Equals
  • из-за тонких различий, вызванных нормализацией или порядком операций.

Я проверил, что при добавлении одних и тех же элементов в словарь в другом порядке создается другой поток.Я полагаю, вы бы посчитали 2 словаря с одинаковым содержанием «равными».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...