代码之家  ›  专栏  ›  技术社区  ›  Dan H

使用陈述问题

  •  5
  • Dan H  · 技术社区  · 16 年前

    我有两个问题。

    1) 你应该总是在连接上使用using语句吗?所以,我会在连接上使用它,然后在连接中的读卡器上使用另一个?所以我将使用两个using语句。

    2) 假设您在连接上使用using语句,并在连接上返回读取器。所以有两个using语句。它是创建两个Try{}Finally{}块还是只创建一个?

    谢谢!

    6 回复  |  直到 16 年前
        1
  •  4
  •   Oded    16 年前
    1. 你应该经常使用 using 对象实现时的语句 IDisposable

    2. 它将创建两个嵌套的 try{}finally{} 阻碍。

        2
  •  7
  •   Joel Coehoorn    15 年前

    这里要小心。你应该 总是 在上有using语句 实现IDisposable的本地对象。这不仅包括连接和读卡器,还包括命令。但有时确实很棘手 哪里 这句话的意思是。如果你不小心,它会引起问题。例如,在下面的代码中,using语句将在您使用它之前关闭读卡器:

    DataReader MyQuery()
    {
        string sql="some query";
        using (var cn = new SqlConnection("connection string"))
        using (var cmd = new SqlCommand(sql, cn))
        {
            cn.Open();
            using (var rdr = cmd.ExecuteReader())
            {
                return rdr;
            }
        }
    }
    

    DataReader MyQuery()
    {
        string sql="some query";
        using (var cn = new SqlConnection("connection string"))
        using (var cmd = new SqlCommand(sql, cn))
        {
            cn.Open();
            return cmd.ExecuteReader();
        }
    }
    
    using (var rdr = MyQuery())
    {
        while (rdr.Read())
        {
            //...
        }
    }
    

    当然,你仍然需要小心你的连接,这意味着记住在你使用函数的地方写一个using块。

    选项二只是在方法本身中处理查询结果,但这打破了数据层与程序其余部分的分离。第三个选项是MyQuery()函数接受Action类型的参数,您可以在while(rdr.Read())循环中调用该参数,但这很尴尬。

    IEnumerable<IDataRecord> MyQuery()
    {
        string sql="some query";
        using (var cn = new SqlConnection("connection string"))
        using (var cmd = new SqlCommand(sql, cn))
        {
            cn.Open();
            using (var rdr = cmd.ExecuteReader())
            {
                while (rdr.Read())
                  yield return rdr;
            }
        }
    }
    

    现在一切都将正确关闭,处理它的代码都在一个地方。您还可以得到一个很好的好处:查询结果可以很好地与任何linq操作符一起工作。

    //part of the data layer
    private static IEnumerable<IDataRecord> Retrieve(string sql, Action<SqlParameterCollection> addParameters)
    {
        //DL.ConnectionString is a private static property in the data layer
        // depending on the project needs, it can be implementing to read from a config file or elsewhere
        using (var cn = new SqlConnection(DL.ConnectionString))
        using (var cmd = new SqlCommand(sql, cn))
        {
            addParameters(cmd.Parameters);
    
            cn.Open();
            using (var rdr = cmd.ExecuteReader())
            {
                while (rdr.Read())
                  yield return rdr;
            }
        }
    }
    

    然后我将在数据层中使用它,如下所示:

    public IEnumerable<IDataRecord> GetFooChildrenByParentID(int ParentID)
    {
        //I could easily use a stored procedure name instead, and provide overloads for commandtypes.
        return Retrieve(
            "SELECT c.* 
             FROM [ParentTable] p 
             INNER JOIN [ChildTable] c ON c.ParentID = f.ID 
             WHERE f.ID= @ParentID", p => 
           {
              p.Add("@ParentID", SqlDbType.Int).Value = ParentID;
           }
         );
    }
    
        3
  •  5
  •   Thomas Levesque    16 年前

    关于连接的声明?所以,我会的 联系?所以我会用两个

    是的,因为他们实施 IDisposable . 别忘了一个 using 命令上的语句:

    using (DbConnection connection = GetConnection())
    using (DbCommand command = connection.CreateCommand())
    {
        command.CommandText = "SELECT FOO, BAR FROM BAZ";
        connection.Open();
        using (DbDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                ....
            }
        }
    }
    

    关于连接的声明以及 读卡器返回 声明。它创造了两个吗 试试{}最后{}块还是一块?

    每个 使用 语句将创建自己的 try/finally 块

        4
  •  2
  •   Cade Roux    16 年前

    避免 当连接用于 asynchronous ADO.NET methods

        5
  •  1
  •   Nick Craver    16 年前

    回答每一个问题:

    1) 是的,这将是最好的做法,尽快处理这两个。

    2) using() 将创建两个块,以相同的顺序包装在一起。它将首先处理内部对象(读卡器),然后使用(连接)从外部处理对象。