2017-01-18 1 views
0

Ich möchte ein ProtoBuffer-Objekt bei der Serialisierung komprimieren und bei der Deserialisierung dekomprimieren. Unglücklicherweise bietet C# stdlib nur Komprimierungsroutinen, die auf Streams und nicht auf Byte [] arbeiten, was es ein bisschen unessery verböser macht als einen Funktionsaufruf. Mein bisheriger Code:Disponieren von MemoryStreams und GZipStreams

class MyObject{ 
public string P1 {get; set;} 
public string P2 {get; set;} 
// ... 

public byte[] Serialize(){ 
    var builder = new BinaryFormat.MyObject.Builder(); 
    builder.SetP1(P1); 
    builder.SetP2(P2); 
    // ... 

    // object is now build, let's compress it. 
    var ms = new MemoryStream(); 
    // Without this using, the serialisatoin/deserialisation Tests fail 
    using (var gz = new GZipStream(ms, CompressionMode.Compress)) 
    { 
    builder.Build().WriteTo(gz); 
    } 
    return ms.ToArray(); 
} 

public void Deserialize(byte[] data) 
{ 
    var ms = new MemoryStream(); 
    // Here, Tests work, even when the "using" is left out, like this: 
    (new GZipStream(new MemoryStream(data), CompressionMode.Decompress)).CopyTo(ms); 
    var msg = BinaryFormat.MachineInfo.ParseFrom(ms.ToArray()); 

    P1 = msg.P1; 
    P2 = msg.P2; 
    // ... 
} 
} 

Beim Umgang mit Streams scheint es, dass man sich manuell um die Entsorgung der Objekte kümmern muss. Ich frage mich, warum das so ist, ich würde erwarten, dass GZipStream vollständig verwaltet wird. Und ich frage mich, ob Deserialize nur durch Zufall funktioniert und ob ich die MemoryStreams auch entsorgen sollte.

Ich weiß, dass ich dieses Problem wahrscheinlich lösen könnte, indem ich einfach eine dritte Partei Kompressions-Bibliothek verwende, aber das ist etwas neben dem Punkt dieser Frage.

+0

Wenn ich mich recht erinnere, wird ein 'MemoryStream' entsorgt, wenn es ein Objekt besitzt, in diesem Fall wird der' GZipStream' entsorgt. Oder das könnte nur für 'Image's ... sein. – TheLethalCoder

+0

Nun nimm es als Lernkurve, wenn etwas' IDisposable' implementiert, sollte es entsorgt werden, idealerweise mit 'using'. Schreiben Sie Code, um Objekte ordnungsgemäß zu verwenden und zu entfernen, und Sie hätten das Problem von Anfang an nicht erkannt. – TheLethalCoder

+0

@TheLethalCoder [nicht immer] (https://blogs.msdn.microsoft.com/pfxteam/2012/03/25/do-i-need-to-dispose-of-tasks/), nehmen Sie 'Task' zum Beispiel Es ist IDisposeable, aber es ist Seite für die Funktion sagt [Sie müssen es nicht tun] (https://msdn.microsoft.com/en-us/library/dd270681 (v = vs.110) .aspx # Anchor_2), wenn .NET 4.5 oder höher als Targeting verwendet wird. –

Antwort

0

GZipStream muss entsorgt werden, damit es die letzten Komprimierungsblöcke aus dem Puffer in den zugrunde liegenden Stream leert, es ruft auch den Stream auf, den Sie übergeben haben, außer Sie verwenden die Überladung that takes in a bool and you pass in false.

Wenn Sie die Überlast verwenden, die MemoryStream nicht entsorgt hat, ist es nicht so kritisch, die MemoryStream entsorgt zu haben, weil es seinen internen Puffer nirgendwo schreibt. Das einzige, was es tut, ist, einige Flags zu setzen und ein Task Objekt auf null zu setzen, so dass es früher GCed werden kann, wenn die Stream-Lebensdauer länger als der Dispose-Punkt ist.

protected override void Dispose(bool disposing) 
    { 
     try { 
      if (disposing) { 
       _isOpen = false; 
       _writable = false; 
       _expandable = false; 
       // Don't set buffer to null - allow TryGetBuffer, GetBuffer & ToArray to work. 
#if FEATURE_ASYNC_IO 
       _lastReadTask = null; 
#endif 
      } 
     } 
     finally { 
      // Call base.Close() to cleanup async IO resources 
      base.Dispose(disposing); 
     } 
    } 

Auch, obwohl der Kommentar sagt „Call base.Close(), um Bereinigung async IO Ressourcen“ die Basis dispose Funktion aus der Stream Klasse gar nichts tut.

protected virtual void Dispose(bool disposing) 
    { 
     // Note: Never change this to call other virtual methods on Stream 
     // like Write, since the state on subclasses has already been 
     // torn down. This is the last code to run on cleanup for a stream. 
    } 

Alles, was gesagt wird, wenn ein GZipStream Dekomprimieren können Sie wahrscheinlich weg mit nicht aus dem gleichen Grund Entsorgung nicht den Memory entsorgen, wenn Dekomprimierung nicht Bytes überall puffert also keine ist müssen irgendwelche Puffer spülen.

Verwandte Themen