使用“using"太多了

本文关键字:太多 quot using 使用 | 更新日期: 2023-09-27 17:50:35

给出以下代码,我认为不再需要finally块来关闭读取器或连接(如果它仍然可用)。使用这么多嵌套的"using"语句有什么好处或坏处吗?还是走最后一条路?

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

使用“using"太多了

确保在using块完成时释放资源。每MSDN:

using语句允许程序员指定when对象即使用资源应释放他们。提供给使用者的对象语句必须实现IDisposable接口。这个接口提供Dispose方法,该方法应该释放对象的资源。

using语句可以在using结束时退出语句是否已达到抛出异常并离开控制结束前的语句块声明。

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

如果你不喜欢这个标识符,那么你可以像这样重写它:

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

参见c#中嵌套语句

你真的知道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()本身-但你必须验证,例如。net反射器

正如你在评论中所要求的:

  1. 我不相信有一个大的catch是一个好的选择…你明确地知道什么地方会出错——把它分成几个catch
  2. 处理这些异常没有完成日志记录。根据环境(有状态还是无状态),您需要处理它(重新创建连接、再次查询等等)。在一个无状态的环境中,重试是没有意义的…当数据库消失时,您有哪些替代方案?
  3. 这只是一个美容问题,还是你真的想知道引擎盖下发生了什么?如果是化妆用的……pfuh……如果它更接近核心,我不会关心人们的答案,而是用分析器来寻找性能:)并且会用反射工具做一些调查
  4. 你的代码基本上看起来很好-我不知道你为什么关心太多的using语句:)…1

如果使用的是"using"块,则不需要使用finally

关闭读取和连接。

理解c#中的using块

代码

使用系统;使用System.Collections.Generic;使用来;使用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接口

除了代码缩进之外,我不知道还有什么缺点。这样做的好处很明显,你不需要担心对象的处理问题,因为只要使用大括号,对象就会被处理掉。

我注意到在你的错误处理程序,你正在传递什么看起来像方法的名称。对于更通用的方法,您可以将其添加到工具箱中,或者创建一个类似于下面的代码片段来自动获取方法和类名。您可以使用反射来获取这些细节。

ErrorHandler.Handler.HandleError(ex, System.Reflection.MethodBase.GetCurrentMethod().Name, System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName);

我认为你的代码很好,但我个人宁愿重构一个using子句来分离函数,因为有5个连续的花括号(即})会使代码可读性降低。但这是我的观点-我喜欢保持缩进的水平尽可能低