2017-11-02 9 views
1

Ich bin eine Klasse zu entwickeln, die FTTP- Anfragen senden kann, hat es eine Dienstprogramm-Methode, die verschiedenen Arten von FTP-Methoden ausführen:Ist es eine gute Übung, eine leere using-Anweisung zu verwenden, um ein verfügbares Objekt in C# zu schließen?

private FtpWebResponse DoFttpRequest(Uri uri, NetworkCredential credentials, string method, string file = null) 
{ 
    var request = (FtpWebRequest)WebRequest.Create(uri); 
    request.Credentials = credentials; 
    request.Method = method; 

    if (!string.IsNullOrEmpty(file)) 
    { 
     using (var stream = request.GetRequestStream()) 
     using (var writer = new StreamWriter(stream)) 
     { 
      writer.Write(file); 
     } 
    } 

    return (FtpWebResponse)request.GetResponse(); 
} 

Wie Sie sehen können, ist diese Methoden ftp Methode ausgeführt und gibt Antwort Strom der Anrufer. Hier ist die Client-Methode, die diese Methode verwendet Zeichenfolge Inhalt in einer Datei über FTP zu schreiben:

public void WriteToFile(string path, string contents) 
{ 
    var uri = new Uri(path); 
    using (var ftpResponse = DoFttpRequest(uri, _credentials, Ftp.UploadFile, contents)) { } 
} 

Wie Sie sehen können, hier bin ich mit leeren Anweisung using (var ftpResponse = DoFttpRequest(uri, _credentials, Ftp.UploadFile, contents)) { } des empfangenen Strom zu entsorgen. Ist das ein guter Ansatz, um Objekte so zu entsorgen? Ist es überhaupt notwendig, diesen Strom zu entsorgen, da er wahrscheinlich sowieso vom Müllsammler entsorgt wird?

+1

Warum brauchen Sie eine Referenz, wenn Sie sie nicht benutzen? Ich würde einfach schreiben 'DoFttpRequest (neue Uri (Pfad), _Credentials, Ftp.UploadFile, Inhalt)' –

+3

Es ist notwendig, es zu entsorgen. Anstatt zu verwenden, können Sie 'DoFttpRequest (..). Dispose()' tun. Wenn Sie leer verwenden mit - keine Notwendigkeit, Variable zu deklarieren: 'using (DoFtpRequest (...)) {}'. – Evk

+0

Es scheint mir, dass die Frage nichts mit 'ftp' oder' webrequest' zu tun hat, es geht eher um 'using' im Allgemeinen – Rafalon

Antwort

5

Ist es auch notwendig, diesen Strom zu entsorgen, da es wahrscheinlich vom Garbage Collector ohnehin

entsorgt werden Sie diesen einfachen Code verwenden können, um zu sehen, wie man es nicht entsorgen Antwortstrom vollständig Anwendung brechen könnte . Ich benutze HTTP-Anfrage anstelle von ftp für simplicity des Testens, aber das gilt gleichermaßen für FTP-Anfragen.

public class Program { 
    static void Main(string[] args) { 
     // this value is *already* 2 by default, set for visibility 
     ServicePointManager.DefaultConnectionLimit = 2; 
     // replace example.com with real site 
     DoFttpRequest("http://example.com"); 
     DoFttpRequest("http://example.com"); 
     DoFttpRequest("http://example.com"); 
     Console.ReadLine(); 
    } 

    private static HttpWebResponse DoFttpRequest(string uri) { 
     var request = (HttpWebRequest) WebRequest.Create(uri); 
     var response = (HttpWebResponse) request.GetResponse(); 
     Console.WriteLine("got response"); 
     return response; 
    } 
} 

Beachten Sie, dass Sie nicht HttpWebResponse entsorgen. Was passiert, ist, dass Sie 2 "Antwort erhalten" Nachrichten in der Konsole sehen werden und dann wird die Anwendung hängen bleiben, wenn Sie versuchen, die 3. Antwort zu erhalten. Das liegt daran, dass die Anzahl der gleichzeitigen Verbindungen pro Endpunkt (pro Host) 2 ist. Während also 2 Verbindungen zum Host (example.com hier) in Bearbeitung sind, muss die nächste Verbindung zum selben Host auf ihren Abschluss warten. Da Sie keine Antwort zur Verfügung haben, werden diese Verbindungen nicht "abgeschlossen", bis GC sie erfasst. Bis dahin - Ihre Anwendung hängt und schlägt dann nach Zeitüberschreitung fehl (wenn request.Timeout auf eine vernünftige Zeit eingestellt ist). Alle nachfolgenden Anforderungen hängen ebenfalls und scheitern dann nach Zeitüberschreitung. Wenn Sie Antworten entsorgt haben, wird die Anwendung wie erwartet funktionieren.

Also immer Dinge wegwerfen, die Einweg sind. Verwenden von Block ist nicht erforderlich, können Sie einfach DoFtpRequest(..).Dispose() tun. Aber wenn Sie lieber leer mit - mindestens keine unnötige Variable deklarieren, tun Sie einfach using (DoFttpRequest(..)) {}.Eine Sache zu beachten, wenn die Wahl zwischen leer mit und Dispose ist die Möglichkeit der Null von DoFtpRequest zurückgegeben wird, denn wenn es Null zurückgibt - Explizite Dispose wird NullReferenceException werfen, während leere Verwendung wird einfach ignorieren (Sie können DoFttpRequest(...)?.Dispose(); tun, wenn Sie NULL aber erwarten möchte nicht mit verwenden).

+0

Der Aufruf von 'Dispose()' erfolgt nicht, wenn eine Ausnahme ausgelöst wird. Es sei denn, Sie wickeln Ihren Anruf in einen try-finally-Block und rufen ihn dort an. Und das ist genau das, was ein Benutzungsblock für Sie tut. – thehennyy

+2

@thehennyy aber hier Block verwenden ist leer. Wenn in 'DoFttpRequest' eine Ausnahme auftritt, gibt es nichts zu beseitigen, es wird noch kein Wert zurückgegeben. Wenn wir Wert zurückgegeben haben, entsorgen wir es sofort. – Evk

-2

Mit der Anweisung wird tatsächlich eine Art Code ausgeführt und dann einfach die Dispose-Methode aufgerufen. Deshalb kann man nur Typen verwenden, die von IDisposible-Schnittstelle erben (in den meisten Fällen)

Sie müssen also nicht wirklich verwenden Anweisung verwenden. Einfach mal anrufen

DoFttpRequest(uri, _credentials, Ftp.UploadFile, contents)).Dispose()

Wenn Sie selbst den Garbage Collector automatisch verfügt es nach dem Umfang abgeschlossen Entsorgen und Objekt nicht. Sie müssen nicht viel über Speicher denken, wenn Sie High-Level-Sprachen wie C#, java verwenden ... Sie heißen Speicher verwaltete Sprachen. Sie kümmern sich um die Art von Personal für Sie.

+0

Nicht wirklich. Wenn die Methode eine Ausnahme auslöst, wird sie nicht entfernt. Deshalb sollte er "using" verwenden. – Marco

+0

"Garbage Collector entsorgt automatisch, nachdem der Bereich abgeschlossen wurde" Nicht wahr, GC kann nur verwaltete Ressourcen verarbeiten. Die Implementierung von 'IDisposable' ist nur sinnvoll für * unmanaged * Ressourcen. Sie müssen 'Dispose' aufrufen, GC wird das nicht für Sie tun. – HimBromBeere

+0

Wenn Sie eine Anweisung verwenden und den Prozess beenden, wird sie auch nicht gelöscht. Sie müssen die Ausnahmen behandeln. Und Frage ist nicht über Ausnahmen :) oder ich kann einfach meine Antwort mit dem Aufruf dispose-Methode in endlich blockieren ändern ... Aber wie ich sage, wenn Sie den Prozess schließlich Block töten werden nicht – ArgeKumandan

Verwandte Themen