使用陈述问题

Dan*_*n H 5 .net c# using-statement

我有两个问题.

1)您是否应始终在连接上使用using语句?那么,我会在连接上使用它,然后在连接中的读者上使用另一个?所以我将使用两个using语句.

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

谢谢!

Joe*_*orn 7

这里要小心.您应该始终任何实现IDisposable的本地对象上使用using语句.这不仅包括连接和读者,还包括命令.但有时候,使用语句的确切位置可能会很棘手.如果你不小心它可能会导致问题.例如,在随后的代码中,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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

相反,您有四种选择.一种是等到创建使用块,直到你调用该函数:

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())
    {
        //...
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,你仍然需要小心你的连接,这意味着记住在你使用该功能的任何地方编写一个使用块.

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

我通常更喜欢选项四:将数据读取器转换为IEnumerable,如下所示:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在一切都将正确关闭,处理它的代码都在一个地方.您还可以获得一个很好的奖励:您的查询结果将适用于任何linq运算符.

最后,我正在玩的新内容,以便下次我构建一个将IEnumerable与传递委托参数相结合的全新项目:

//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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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;
       }
     );
}
Run Code Online (Sandbox Code Playgroud)

  • "你应该总是在任何实现IDisposable的对象上使用声明":这不完全正确......你需要为实现IDisposable的**本地**变量做到这一点,但对于类成员则不需要,因为它们通常会在课堂上的其他地方重复使用.但是,在这种情况下,类本身应该实现IDisposable,并在其Dispose方法中处理所有IDisposable成员 (2认同)

Tho*_*que 5

1)您是否应始终在连接上使用using语句?那么,我会在连接上使用它,然后在连接中的读者上使用另一个?所以我将使用两个using语句.

是的,因为他们实施了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())
        {
            ....
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

每个using语句都会创建自己的try/finally


Ode*_*ded 4

  1. using当对象实现IDisposable. 这包括连接。

  2. 它将创建两个嵌套try{}finally{}块。