【问题标题】:Refactor code into using statement将代码重构为 using 语句
【发布时间】:2009-05-26 08:21:14
【问题描述】:

我有一个 dal 层,其中包含很多方法,它们都调用存储过程,一些返回列表(因此使用 SqlDataReader),其他只有特定值。

我有一个创建 SqlCommand 的辅助方法:

    protected SqlCommand CreateSprocCommand(string name, bool includeReturn, SqlDbType returnType)
    {
        SqlConnection con = new SqlConnection(this.ConnectionString);
        SqlCommand com = new SqlCommand(name, con);
        com.CommandType = System.Data.CommandType.StoredProcedure;

        if (includeReturn)
            com.Parameters.Add("ReturnValue", returnType).Direction = ParameterDirection.ReturnValue;

        return com;
    }

现在我的平均(过度简化)方法体看起来像:

SqlCommand cmd = CreateSprocCommand("SomeSprocName"); //an override of the above mentioned method
try {
   cmd.Connection.Open();
   using (var reader = cmd.ExecuteReader()) {
       //some code looping over the recors
   }
   //some more code to return whatever needs to be returned
}
finally {
   cmd.Connection.Dispose();
}

有没有办法重构它,这样我就不会丢失我的辅助函数(它会做很多其他重复的工作),但还能使用using

【问题讨论】:

    标签: c# using sqlconnection sqlcommand


    【解决方案1】:

    一种方法是将其从返回命令更改为接受使用命令的委托:

    protected void ExecuteSproc(string name,
                                SqlDbType? returnType,
                                Action<SqlCommand> action)
    {
        using (SqlConnection con = new SqlConnection(this.ConnectionString))
        using (SqlCommand com = new SqlCommand(name, con))
        {
            con.Open();
            com.CommandType = System.Data.CommandType.StoredProcedure;
    
            if (returnType != null)
            {
                com.Parameters.Add("ReturnValue", returnType.Value).Direction = 
                    ParameterDirection.ReturnValue;
            }
            action(com);
        }
    }
    

    (请注意,我还删除了includeReturn 参数并改为将returnType 设为可为空。只需将null 传递给“无返回值”即可。)

    您可以将其与 lambda 表达式(或匿名方法)一起使用:

    ExecuteSproc("SomeName", SqlDbType.DateTime, cmd =>
    {
        // Do what you want with the command (cmd) here
    });
    

    这样处理与创建在同一个地方,调用者不需要担心它。我非常喜欢这种模式 - 现在我们有了 lambda 表达式,它变得更简洁了。

    【讨论】:

    • 在这种情况下打开连接作为副作用可能是有意义的......(因为它作为副作用被关闭)
    • 太好了,已经包含了连接的开启!将开始重构 +/- 200 种方法...
    • 我们需要一个新词来描述这样的想法......类似于“superfablutastic”的东西
    【解决方案2】:

    你可以这样做:

    protected static SqlCommand CreateSprocCommand(SqlConnection con, string name, bool includeReturn, SqlDbType returnType)
    {
        SqlCommand com = new SqlCommand(name, con);
        com.CommandType = System.Data.CommandType.StoredProcedure;
    
        if (includeReturn)
            com.Parameters.Add("ReturnValue", returnType).Direction = ParameterDirection.ReturnValue;
    
        return com;
    }
    

    然后这样称呼它:

    using (SqlConnection con = new SqlConnection(this.ConnectionString))
    using (SqlCommand cmd = CreateSprocCommand(con, "SomeSprocName", true, SqlDbType.Int)
    {
        cmd.Connection.Open();
        using (var reader = cmd.ExecuteReader())
        {
            //some code looping over the recors
        }
        //some more code to return whatever needs to be returned
    }
    

    【讨论】:

    • 啊哈,所以我不是唯一一个这样格式化嵌套使用的人!
    【解决方案3】:

    你可以嵌套 using 语句:

    using (SqlCommand cmd = CreateSprocCommand("..."))
    {
      using (var connection = cmd.Connection)
      {
         connection.Open();
         using (var reader = cmd.ExecuteReader())
         {
             ...
         }
         ...
      }
    }
    

    【讨论】:

    • 我通常会省略外部层级的大括号并将它们缩进到同一层级,以传达我打算将所有以这种方式格式化的一次性用品一起使用。我还没有完全决定这是一个坏主意还是一个非常糟糕的主意;-)
    【解决方案4】:

    怎么样:

    using (SqlCommand cmd = CreateSprocCommand("whatever"))
    {
      cmd.Connection.Open();
      using (var reader = cmd.ExecuteReader())
      {
       //blabla
      }
    }
    

    【讨论】:

    • 我不认为释放命令会释放连接
    • cmd.Dispose() 调用 cmd.Connection.Dispose() 吗?
    【解决方案5】:

    这是你的意思吗?

    using (SqlCommand cmd = CreateSprocCommand("SomeSprocName"))
    {
        cmd.Connection.Open();
        using (var reader = cmd.ExecuteReader()) 
        {
            //some code looping over the recors
        }
    }
    

    【讨论】:

    • 和 Rune 一样,这不会关闭连接。
    猜你喜欢
    • 2020-12-08
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 2019-02-05
    • 2021-10-13
    • 1970-01-01
    • 2014-06-18
    • 1970-01-01
    相关资源
    最近更新 更多