将一个Using块包含在另一个Using块内 - 这是过度设计吗?

4

我在项目中有一段代码,在一个using块内包含了另一个using块,我想知道这是好的做法还是过度设计(请注意,我明白这只是一个非常简单的代码片段,仅用于说明):

protected void Submit_Click(object sender, EventArgs e)
    {
        try
        {
            using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["RegConnectionString"].ConnectionString))
            {
                cn.Open();

                string cmdStr = "SELECT COUNT(*) FROM REGISTRATION WHERE UserName ='" + this.TextBoxUN.Text + "' ";
                using (SqlCommand selectUser = new SqlCommand(cmdStr, cn))
                {
                    int temp = Convert.ToInt32(selectUser.ExecuteScalar().ToString());

                    if (temp == 0)
                    {
                        string insCmd = "Insert INTO REGISTRATION (UserName, Password, EmailAddress, FullName, Country) VALUES (@UserName, @Password, @EmailAddress, @FullName, @Country)";
                        using (SqlCommand insertUser = new SqlCommand(insCmd, cn))
                        {
                            try
                            {
                                insertUser.Parameters.AddWithValue("@UserName", this.TextBoxUN.Text);
                                insertUser.Parameters.AddWithValue("@Password", this.TextBoxPass.Text);
                                insertUser.Parameters.AddWithValue("@EmailAddress", this.TextBoxEA.Text);
                                insertUser.Parameters.AddWithValue("@FullName", this.TextBoxFN.Text);
                                insertUser.Parameters.AddWithValue("@Country", this.DropDownListCountry.SelectedItem.ToString());

                                insertUser.ExecuteNonQuery();
                                Response.Redirect("~/Login.aspx");
                            }
                            catch (Exception ex)
                            {
                                Response.Write(ex.Message);
                            }
                        }
                    }
                    else
                    {
                        Response.Write("User already Exists in Database");
                    }
                }
            }
        }
        catch (Exception ex)
        {
            Response.Write(ex.Message);
        }
    }
}

1
对于所有实现 IDisposable 的内容,请使用 using 并尽快进行处理。 - Tim Schmelter
略微偏离问题,但您可以通过将内部代码块提取为单独的私有方法来减少嵌套using块的混乱。这样,逻辑不再嵌套得难以阅读,但您仍然具有正确的外部'using'块来处理资源的释放。 - Dan Bryant
@DanBryant 谢谢,实际上我有一个库类来处理所有这些“低级”操作,但为了使我的帖子更易于阅读和理解,我选择了这种方式。 - Mark Kram
只是一个快速的评论 - 异常捕获是一个不好的想法。除非你把它们纯粹用于调试并计划稍后删除它们,否则应该从代码中删除它们。 - Enigmativity
3个回答

11

是的,这是一个好习惯。在最小的范围内处理掉东西,否则你就要让垃圾回收器在相当长的时间后才能处理它。


太好了,我没想到它会有影响。 - Mark Kram
垃圾收集器(GC)从不处理对象的释放。它仅仅释放内存。你必须明确地直接或通过自己的终结器来处理对象的释放。 - Enigmativity

1
当然可以嵌套using语句。每个using语句只适用于一个对象,因此如果需要处理多个对象,使用多个using语句。
此外,您可以通过在打开第二个命令之前关闭第一个命令来减少嵌套。
int temp;
using (SqlCommand selectUser = new SqlCommand(cmdStr, cn))
{
    temp = Convert.ToInt32(selectUser.ExecuteScalar().ToString());
}
if (temp == 0)
{
    string insCmd = ...;
    using (SqlCommand insertUser = new SqlCommand(insCmd, cn))
    {
        ...
    }
}

1

我完全同意在处理嵌套的可释放对象时使用using语句是必须的。

然而,我建议对代码进行进一步修改。为了使您的代码易于阅读、测试和维护,使用函数组合是一个好主意。以下是我如何更改代码主体:

using (var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["RegConnectionString"].ConnectionString))
{
    cn.Open();
    if (checkUserExists(cn, this.TextBoxUN.Text))
    {
        Response.Write("User already Exists in Database");
    }
    else
    {
        addUser(cn, this.TextBoxUN.Text, this.TextBoxPass.Text, this.TextBoxEA.Text, this.TextBoxFN.Text, this.DropDownListCountry.SelectedItem.ToString());
        Response.Redirect("~/Login.aspx");
    }
    cn.Close();
}

这段代码更加紧凑,更容易理解正在发生的事情。

在此代码之前,您需要定义checkUserExistsaddUser lambda函数,如下所示:

Func<SqlConnection, string, bool> checkUserExists = (cn, un) =>
{
    var query = "SELECT COUNT(*) FROM REGISTRATION WHERE UserName = @UserName";
    using (var command = new SqlCommand(query, cn))
    {
        command.Parameters.AddWithValue("@UserName", un);
        return Convert.ToInt32(command.ExecuteScalar().ToString()) != 0;
    }
};

Action<SqlConnection, string, string, string, string, string> addUser = (cn, un, pw, e, fn, c) =>
{
    string query = "Insert INTO REGISTRATION (UserName, Password, EmailAddress, FullName, Country) VALUES (@UserName, @Password, @EmailAddress, @FullName, @Country)";
    using (var command = new SqlCommand(query, cn))
    {
        command.Parameters.AddWithValue("@UserName", un);
        command.Parameters.AddWithValue("@Password", pw);
        command.Parameters.AddWithValue("@EmailAddress", e);
        command.Parameters.AddWithValue("@FullName", fn);
        command.Parameters.AddWithValue("@Country", c);

        command.ExecuteNonQuery();
    }
};

每个都非常简单,其意图清晰且易于理解。

由于它们是lambda表达式,它们不会用不必要的方法堵塞您的类 - 一切都包含在一个方法中。漂亮,整洁和干净。

当然,它们都使用using语句。

希望这有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接