public static bool DeserializeInto <T>(ref T target, Stream serializedObjectReader, out byte[] lastKnownHash)
        {
            lastKnownHash = NullHash;

            if (serializedObjectReader.Length != 0)
            {
                serializedObjectReader.Seek(0, SeekOrigin.Begin);

                using (GZipStream decompressor = new GZipStream(serializedObjectReader, CompressionMode.Decompress))
                    using (SHA256StreamHasher readAndHash = new SHA256StreamHasher(decompressor))
                    {
                        BinaryFormatter formatter = new BinaryFormatter();
                        try
                        {
                            target = (T)formatter.Deserialize(readAndHash);
                        }
                        catch (InvalidDataException)
                        {
                            return(false); // Not valid GZIP compressed data
                        }
                        catch (SerializationException)
                        {
                            return(false); // Not valid BinaryFormatter serialized object
                        }
                        lastKnownHash = readAndHash.ComputeHash();
                    }
            }

            return(true);
        }
        /// <summary>
        /// Returns true if the serialized representation of obj has changed since the lastKnownHash
        /// was produced.
        /// </summary>
        public static bool ModifiedSince <T>(T obj, byte[] lastKnownHash, out byte[] newHash)
        {
            if (obj == null)
            {
                newHash = NullHash;
            }
            else
            {
                SHA256StreamHasher hasher = new SHA256StreamHasher();
                SerializeIntoStreamImpl(obj, hasher, false);
                newHash = hasher.ComputeHash();
            }

            return((lastKnownHash == null) || !HashEquals(newHash, lastKnownHash));
        }