2016-11-18 3 views
0

Es gibt viele Beispiele für Code, wenn die folgende Konstruktion von Implementierungs-E/A-Operationen mit der Stream-Klasse verwendet wird. Wie folgt:Warum sollte eine neue Instanz von Stream pro E/A-Vorgang erstellt werden? (C#)

Wenn wir ReadFileBro aufrufen, erstellt es immer neue Eigenschaften von Stream-Beton-Implementierungen. Sobald die Operation wiederholt wird, werden die Einsen gelöscht.

Warum kann ich meinen StreamReader nicht einfach einmal erstellen und als Eigenschaft einer Klasse zur Multiplikation speichern?

Kürzlich habe ich eine kleine App für die Client-Server-Interaktion über SSH (mit [SSH.NET] [1]) bereitgestellt. Diese (vereinfacht) Code gearbeitet falsch:

class MyConnection 
{ 
    ShellStream myStream = client.CreateShellStream(...);//it represents Stream between client and server, create it as single instance for each calling SendCommand 

    void SendCommand(string command) 
    { 
     myStream.WriteLine(command);//send a command to server 
     string readed = null; 
     while (myStream.DataAvailable) 
     { 
      output = myStream.Read();//get data from server 
     } 
    } 
} 

jedoch dieser Code funktioniert gut:

class MyConnection 
{ 
    void SendCommand(string command) 
    { 
     myStream.WriteLine(command); 
     using(var myStream = client.client.CreateShellStream(...)) 
     { /* get data from server */ } 
    } 
} 

Wie konnte das passieren?

Antwort

0

Der Hauptgrund, dass Sie einen Stream nach der Verwendung schließen und einen neuen erstellen, liegt an dem Sperren der Ressourcen und dem Freigeben der Ressourcen auf der tatsächlichen Ressource. In der Regel ist eine lange Zeit ein IDisposable Objekt zu halten eine schlechte Praxis.

Die Kosten für das Erstellen eines neuen Objekts sind sehr niedrig und gewährleisten eine ordnungsgemäße Ressourcenverwaltung.

Edit: Im Falle Ihrer spezifischen Situation funktioniert Ihr Weg am wahrscheinlichsten, jedoch sollten Sie IDisposable ordnungsgemäß implementieren. Unten ist ein High-Level Beispiel

class MyConnection : IDisposable 
{ 
    ShellStream myStream = client.CreateShellStream(...);//it represents Stream between client and server, create it as single instance for each calling SendCommand 

    void SendCommand(string command) 
    { 
     myStream.WriteLine(command);//send a command to server 
     string readed = null; 
     while (myStream.DataAvailable) 
     { 
      output = myStream.Read();//get data from server 
     } 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      // free managed resources 
      if myStream != null) 
      { 
       myStream .Dispose(); 
       myStream = null; 
      } 
     } 
    } 
} 
+0

In der SSH.NET-Bibliothek befindet sich die ShellStream-Klasse (Client-Server-Änderungsdaten). Diese Klasse weist eine Eigenschaft auf, die ein Ereignis darstellt, das ausgelöst wird, wenn eine neue Nachricht eintrifft. Wenn Dispose() der Instanz von ShellStream aufgerufen wird, können meine Handler dieses Ereignis nicht abonnieren. Kann ich die ShellStream-Instanz in diesem Szenario speichern? – Mergasov

+0

ShellStream ist eine andere Implementierung als der allgemeinere Stream. In Ihrem Fall könnte die Implementierungsoption eine andere Option darstellen. Ich würde jedoch sehr empfehlen, wenn Sie es halten, sollten Sie auch IDisposable selbst implementieren –

0

Ich glaube es wird empfohlen, dass Sie einen Stream initialisieren und es pro Anforderung aus zwei Gründen schließen:

  1. Sie sicher, dass Sie offen und jeden Strom schließen.
  2. Sie haben nicht viele Streams offen, die Probleme verursachen können. Dies ist bei Datenbankverbindungen üblich.
0

Using ist eine kurze Hand zum Erstellen eines Einwegobjekts, das die Ausführung von Operationen auf dem Objekt ermöglicht. Wenn es den using-Block verlässt, führt das Objekt seine Dispose() Methode aus.

IDisposable ist wichtig für Objekte, die entweder externe Ressourcen wie Dateien, Datenbanken usw. verwenden, und es ist extrem wichtig, wo das betreffende Objekt auf nicht verwalteten Code zugreift. Ihr Filestream-Objekt greift zweifellos auf Systemkomponenten der unteren Ebene zu, um auf Dateien zuzugreifen und sie zu lesen/zu schreiben. Der Filestream implementiert IDisposable, weil seine Methode Dispose() private Methoden ausführt, um alle Ressourcen zu schließen, auf die er zugegriffen hat. Dies soll helfen, Speicherlecks, gesperrte Ressourcen und dergleichen zu verhindern.

Ein Objekt, das IDisposable nicht implementiert, wird normalerweise ungültig, wenn das betreffende Objekt den Gültigkeitsbereich verlässt, dh die Codeausführung wurde in eine andere Methode verschoben, in der es nicht mehr auf die Objektinstanz zugreifen kann. Nach kurzer Zeit werden diese Objekttypen vom Garbage Collector als ungültig markiert und automatisch bereinigt, solange keine aktiven Zeiger auf das Objekt vorhanden sind.

IDisposable ist anders, weil wir auf externe Ressourcen zugreifen, auf die der GC keinen Zugriff hat und dennoch den Anwendungsspeicher belegt. Dispose() - Methoden stellen sicher, dass alles manuell aufgeräumt wird. Es ist so, als würde man seinen eigenen Tisch putzen, nachdem man gegessen hat, anstatt einen Kellner dazu zu bringen.

+0

Was ist mit einem Szenario, wenn Stream-Implementierung irgendwelche Ereignisse hat (zum Beispiel, jetzt sind neue Daten gekommen)? Ich kann diese nicht abonnieren, wenn Dispose() für Stream aufgerufen wird – Mergasov

+0

Sie würden das separat speichern und das Ereignis auslösen, nachdem Sie mit dem Stream fertig sind –

Verwandte Themen