使用空的using语句在C#中关闭一次性对象是一种好习惯吗?

时间:2017-11-02 07:58:03

标签: c# ftp dispose using webrequest

我正在开发一个可以发送fttp请求的类,它有一个可以执行不同类型的ftp方法的实用方法:

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();
}

如您所见,此方法执行ftp方法并将响应流返回给调用者。以下是使用此方法通过ftp:

将字符串内容写入文件的客户端方法
public void WriteToFile(string path, string contents)
{
    var uri = new Uri(path);
    using (var ftpResponse = DoFttpRequest(uri, _credentials, Ftp.UploadFile, contents)) { }
}

如您所见,这里我使用空语句using (var ftpResponse = DoFttpRequest(uri, _credentials, Ftp.UploadFile, contents)) { }来处理收到的流。 这是处理这类对象的好方法吗?是否有必要处理这个流,因为它可能会被垃圾收集器处理掉?

2 个答案:

答案 0 :(得分:5)

  

是否有必要处理此流,因为它可能会   无论如何由垃圾收集器处理

您可以使用此简单代码查看如何不处理响应流可能会完全破坏应用程序。我使用http请求而不是ftp来进行测试,但这同样适用于ftp请求。

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;
    }
}

请注意,您没有处置HttpWebResponse。会发生什么,你会看到2"得到回应"控制台和应用程序中的消息将挂起尝试第三次获得响应。这是因为每个端点(每个主机)的并发连接限制是2,所以虽然与主机的2个连接(这里是example.com)是"正在进行中" - 与同一主机的下一次连接必须等待它们完成。因为你没有处理响应 - 这些连接不会被完成"直到GC收集它们。在此之前 - 您的应用程序挂起然后超时失败(如果request.Timeout设置为某个合理的时间)。所有后续请求也会挂起,然后超时失败。如果您处置响应 - 应用程序将按预期工作。

所以总是处理一次性的东西。不需要使用块,您可以DoFtpRequest(..).Dispose()。但是,如果您更喜欢空闲使用 - 至少不要声明不必要的变量,只需执行using (DoFttpRequest(..)) {}即可。在空使用和Dispose之间进行选择时要注意的一件事是DoFtpRequest可能返回null,因为如果它将返回null - 显式Dispose将抛出NullReferenceException而空使用will忽略它(如果你期望空值但不想使用,你可以DoFttpRequest(...)?.Dispose();。)

答案 1 :(得分:-2)

using语句实际上是执行某种代码然后只是调用Dispose方法。 这就是为什么你只能使用它继承IDisposible接口的类型(在大多数情况下)

所以你不必使用using语句。只需致电

即可

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

如果您不自行处理和对象, 垃圾收集器 会在范围完成后自动处理它。 当您使用c#,java等高级语言时,您不必考虑内存...它们被称为 内存管理语言 。他们为你处理那些工作人员。