鉴于以下代码,我认为不再需要finally块来关闭阅读器或连接(如果它仍然可用)。使用这么多嵌套的“使用”语句有什么好处或缺点吗?或者我应该走最后的街区路线?
List<string> platforms = new List<string>();
NpgsqlDataReader reader = null;
try
{
using (NpgsqlConnection conn = new NpgsqlConnection(GetConnectionString()))
{
// Making connection with Npgsql provider
string sql = @"SELECT platforms.""name"" FROM public.""platforms""";
using (NpgsqlCommand command = new NpgsqlCommand(sql))
{
command.Connection = conn;
command.CommandType = System.Data.CommandType.Text;
conn.Open();
using (reader = command.ExecuteReader())
{
while (reader.Read())
{
platforms.Add((string)reader["name"].ToString());
}
}
}
}
}
catch (Exception err)
{
HandleError(err, "GetPlatforms");
}
finally
{
platforms = null;
if (!reader.IsClosed)
{
reader.Close();
}
}
答案 0 :(得分:8)
确保在使用块完成时释放资源。每MSDN:
using语句允许程序员指定何时对象 使用资源应该发布 他们。提供给使用的对象 声明必须执行 IDisposable接口。这个界面 提供Dispose方法,其中 应释放对象的资源。
可以在使用结束时退出using语句 达成或如果是 抛出异常并控制离开 结束前的语句块 声明。
我没有看到您在代码中列出的多个using
语句块有任何问题。它确保释放资源,以及程序员不会忘记的方式。
如果您不喜欢这个标识,那么您可以重写这样的内容:
using (StreamWriter w1 = File.CreateText("W1"))
using (StreamWriter w2 = File.CreateText("W2"))
{
// code here
}
上的这个问题
答案 1 :(得分:3)
你真的知道如何编译using
吗?
取
using (var disposableObject = new DisposableObject())
{
// do something with it
}
get编译为(或多或少):
IDisposable disposableObject = new DisposableObject();
try
{
// do something with it
}
finally
{
if (disposableObject != null)
{
disposableObject.Dispose();
}
}
只是一个想法:在哪些情况下会发生异常?
一个猜测:我想NpgsqlConnection
在.Close()
本身上调用.Dispose()
- 但你必须用eg验证这一点。 .NET Reflector
正如您通过评论所要求的那样:
catch
是一个不错的选择...你明确知道会出现什么问题 - 把它分成几个捕获using
语句:) ...除了pt。 1 答案 2 :(得分:1)
如果您使用“使用”块,则无需最终使用。
只关闭读取和连接。
understanding ‘using’ block in C#
代码
使用System; 使用System.Collections.Generic; 使用System.Linq; 使用System.Text;
namespace BlogSamples
{
class Program
{
static void Main(string[] args)
{
using (Car myCar = new Car(1))
{
myCar.Run();
}
}
}
}
IL代码
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 37 (0x25)
.maxstack 2
.locals init ([0] class BlogSamples.Car myCar,
[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: newobj instance void BlogSamples.Car::.ctor(int32)
IL_0007: stloc.0
.try
{
IL_0008: nop
IL_0009: ldloc.0
IL_000a: callvirt instance void BlogSamples.Car::Run()
IL_000f: nop
IL_0010: nop
IL_0011: leave.s IL_0023
} // end .try
finally
{
IL_0013: ldloc.0
IL_0014: ldnull
IL_0015: ceq
IL_0017: stloc.1
IL_0018: ldloc.1
IL_0019: brtrue.s IL_0022
IL_001b: ldloc.0
IL_001c: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0021: nop
IL_0022: endfinally
} // end handler
IL_0023: nop
IL_0024: ret
} // end of method Program::Main
正如你在这里看到的那样,你使用block是在try ... finally中转换的。但该类必须实现IDispose接口
答案 3 :(得分:1)
除了代码缩进之外,我不知道任何缺点。优势显然是你不必担心处理你的物品,因为一旦使用支架就会被丢弃。
我在你的错误处理程序中注意到你传递了看起来像方法名称的东西。对于更通用的一个,您可以通过添加到工具箱中来使用,或者创建一个类似于以下内容的片段来自动获取方法和类名。您可以使用反射来获取这些详细信息。
ErrorHandler.Handler.HandleError(ex, System.Reflection.MethodBase.GetCurrentMethod().Name, System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName);
答案 4 :(得分:0)
我认为你的代码很好,但我个人宁愿重构一个using子句来分离函数,因为有5个连续的花括号(即})会使代码不易读取。但这是我的观点 - 我喜欢尽可能降低压痕水平。