C# "using" 块

5

我有类似下面的代码...这里有人提到WebClient、Stream和StreamReader对象都可以从使用块中受益。两个简单的问题:

1:如果使用块,这个小片段会是什么样子?我不介意自己做研究,所以资源链接很好,但看一个例子会更快、更容易理解。

2:我想养成良好编码规范的习惯,如果知道一些使用块更好的原因就更好了...是为了不必担心关闭还是还有其他原因?谢谢!

WebClient client = new WebClient();
Stream stream = client.OpenRead(originGetterURL);
StreamReader reader = new StreamReader(stream);

JObject jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine());
string encryptionKey = (string)jObject["key"];
string originURL = (string)jObject["origin_url"];

stream.Close()
reader.Close()

抱歉...看起来代码格式有点混乱了。 - J Benjamin
9个回答

9
using (var client = new WebClient())
using (var stream = client.OpenRead(originGetterURL))
using (var reader = new StreamReader(stream))
{
    var jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine());
    var encryptionKey = (string)jObject["key"];
    var originURL = (string)jObject["origin_url"];
}

或者简单地说:
using (var client = new WebClient())
{
    var json = client.DownloadString(originGetterURL);
    var jObject = Newtonsoft.Json.Linq.JObject.Parse(json);
    var encryptionKey = (string)jObject["key"];
    var originURL = (string)jObject["origin_url"];
}

是的,using块的目的是确保即使抛出异常,Dispose方法也将被调用。 - Darin Dimitrov
@J Benjamin - 处理将始终发生,这只是让您在使用块之后执行任何操作之前强制执行它的方法。 - Robert Levy
2
为什么没有人告诉我,我可以在一个花括号中堆叠using语句。为什么不呢?!? - Nathan Taylor
@JamesSkemp 但这是否相同呢?这些对象是在下一行被处理还是在最外层的大括号之前被处理? - Nathan Taylor
1
@Nathan,它们将在}关闭后被处理,并且按照它们被实例化的相反顺序进行处理。 - Darin Dimitrov
显示剩余3条评论

5
using (WebClient client = new WebClient())
{
    // do work
}

提供了一种方便的语法,确保正确使用IDisposable对象。

来自MSDN:using语句(C#参考)


作为一条规则,当您使用一个IDisposable对象时,应该在using语句中声明和实例化它。using语句以正确的方式调用Dispose方法,并且在Dispose被调用时,它还会导致对象本身立即超出范围。在using块内,对象是只读的,不能被修改或重新分配。

using语句确保即使在调用对象方法时发生异常,也会调用Dispose方法。您可以通过将对象放入try块中,然后在finally块中调用Dispose来实现相同的结果;实际上,这就是编译器如何将using语句转换的方式。


4
using(WebClient client = new WebClient()) {

}

等同于

WebClient client;
try {
    client = new WebClient();
} finally {
    if(client != null) {
        client.Dispose();
    }
}

使用起来更加简单易懂

2

很简单:

使用*using*并不是“良好的实践”,它只是一种更短的方式(语法糖),用于处理你应该处理的对象。例如文件、数据库连接以及在你的情况下网络。

你可以像这样做:

using(WebClient we = new WebClient))
{
//do something with 'we' here
}

这基本上只是一个使用变量we并调用we.Dispose()进行清理的快捷方式。
语法:
using (<Any class that Implements IDisposable>)
{
//use the class
}

你应该看到的其他SO问题:
using关键字和IDisposable接口之间的关系是什么?
在using语句中使用各种类型(C#)


哦,天啊!我没有仔细检查你的代码,不过现在我看到了很多其他的答案 =P 希望我的回答有用! - gideon

1

使用{}块,在闭合大括号处简单地调用Dispose(),或者告诉垃圾回收器可以处理该对象。您可以像这样使用它:

using (WebClient client = new WebClient())
{
    Stream stream = client.OpenRead(originGetterURL); StreamReader reader = new  StreamReader(stream);

    JObject jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine()); string encryptionKey = (string)jObject["key"]; string originURL = (string)jObject["origin_url"];

    stream.Close() reader.Close()
} // 'client' instance gets disposed here

1

类似这样:

using(WebClient client = new WebClient())
using(Stream stream = client.OpenRead(originGetterURL))
StreamReader reader = new StreamReader(stream) {
  JObject jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine());
  string encryptionKey = (string)jObject["key"];
  string originURL = (string)jObject["origin_url"];
}

至于为什么using块很好,比手动调用Dispose更好...想象一下,如果在关闭所有内容的行之前,该using块中的任何代码抛出异常,那会怎样?实质上,您将泄漏IDisposable对象在幕后管理的任何未受管控资源。using确保正确调用Dispose,即使面对异常(通过基本注入适当的try/finally块)。

如果可能的话(即您不必跨范围保留某些IDisposable的生命周期),您应该利用using块,即使没有其他原因,它们也可以减少您必须编写的样板代码量,以确保您自己的代码是安全和正确的。


1

使用块的原因有两个:

  • 它们看起来很好
  • 块内的代码通常可能会抛出异常。因此,您需要使用try-finally

最终,使用块如下所示:

using (Somthing somthing=...)
{
    DoActions(somthing);
}

与以下结构相同:

{Somthing somthing=...
    try
    {
        DoActions(somthing);
    }
    finally
    {
        somthing.Dispose();
    }
}//the outer bracket limits the variable

1

@Darin的回答展示了代码。使用块的好处在于,它会导致编译器生成的代码在退出块之前自动调用“Dispose”方法(以立即释放对象可能正在使用的任何资源),即使在块内部抛出异常也是如此。


1

using 相当于 try.. finally,因此即使在块内抛出异常,处理器也会运行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接