使用“使用”太多了?

时间:2011-04-20 13:07:28

标签: c# .net

鉴于以下代码,我认为不再需要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();
    }
}

5 个答案:

答案 0 :(得分:8)

确保在使用块完成时释放资源。每MSDN

  

using语句允许程序员指定何时对象   使用资源应该发布   他们。提供给使用的对象   声明必须执行   IDisposable接口。这个界面   提供Dispose方法,其中   应释放对象的资源。

     

可以在使用结束时退出using语句   达成或如果是   抛出异常并控制离开   结束前的语句块   声明。

我没有看到您在代码中列出的多个using语句块有任何问题。它确保释放资源,以及程序员不会忘记的方式。

如果您不喜欢这个标识,那么您可以重写这样的内容:

using (StreamWriter w1 = File.CreateText("W1"))
using (StreamWriter w2 = File.CreateText("W2"))
{
      // code here
}

另见nested using statements in C#

上的这个问题

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

只是一个想法:在哪些情况下会发生异常?

  • db消失了:你应该怎么处理?
  • 查询错误:...应该记录

一个猜测:我想NpgsqlConnection.Close()本身上调用.Dispose() - 但你必须用eg验证这一点。 .NET Reflector

正如您通过评论所要求的那样:

  1. 我不相信拥有一个大catch是一个不错的选择...你明确知道会出现什么问题 - 把它分成几个捕获
  2. 处理这些异常不是通过日志记录完成的。根据环境(有状态与非有状态),您需要处理它(重新创建连接,再次查询,......)。处于非有状态的环境中重试大多没有意义......当数据库消失时,你有哪些替代方案?
  3. 这只是一个美化问题还是你真的想知道引擎盖下发生了什么?如果它是一个化妆品...... pfuh ......如果它更多的是核心,我不会关心人们的答案并用剖析器追捕表现:)并且会用反射工具做一些调查
  4. 你的代码基本上看起来很好 - 我没有任何线索为什么你关心过多的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个连续的花括号(即})会使代码不易读取。但这是我的观点 - 我喜欢尽可能降低压痕水平。